diff --git a/AVRestKitFoursquareAPIapp.xcodeproj/project.pbxproj b/AVRestKitFoursquareAPIapp.xcodeproj/project.pbxproj new file mode 100644 index 0000000..bf8e274 --- /dev/null +++ b/AVRestKitFoursquareAPIapp.xcodeproj/project.pbxproj @@ -0,0 +1,648 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 292500721BB42A2B0046AD96 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 292500711BB42A2B0046AD96 /* main.m */; }; + 292500751BB42A2B0046AD96 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 292500741BB42A2B0046AD96 /* AppDelegate.m */; }; + 292500781BB42A2B0046AD96 /* MasterViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 292500771BB42A2B0046AD96 /* MasterViewController.m */; }; + 2925007B1BB42A2B0046AD96 /* DetailViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2925007A1BB42A2B0046AD96 /* DetailViewController.m */; }; + 2925007E1BB42A2B0046AD96 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 2925007C1BB42A2B0046AD96 /* Main.storyboard */; }; + 292500801BB42A2B0046AD96 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2925007F1BB42A2B0046AD96 /* Assets.xcassets */; }; + 292500831BB42A2B0046AD96 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 292500811BB42A2B0046AD96 /* LaunchScreen.storyboard */; }; + 2925008E1BB42A2B0046AD96 /* AVRestKitFoursquareAPIappTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 2925008D1BB42A2B0046AD96 /* AVRestKitFoursquareAPIappTests.m */; }; + 292500991BB42A2C0046AD96 /* AVRestKitFoursquareAPIappUITests.m in Sources */ = {isa = PBXBuildFile; fileRef = 292500981BB42A2C0046AD96 /* AVRestKitFoursquareAPIappUITests.m */; }; + 292500A71BB436AF0046AD96 /* libRestKit.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 292500A61BB436AF0046AD96 /* libRestKit.a */; }; + 292500A91BB436EE0046AD96 /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 292500A81BB436EE0046AD96 /* CFNetwork.framework */; }; + 292500AE1BB4371D0046AD96 /* CoreData.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 292500AA1BB4371D0046AD96 /* CoreData.framework */; }; + 292500AF1BB4371D0046AD96 /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 292500AB1BB4371D0046AD96 /* MobileCoreServices.framework */; }; + 292500B01BB4371D0046AD96 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 292500AC1BB4371D0046AD96 /* Security.framework */; }; + 292500B11BB4371D0046AD96 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 292500AD1BB4371D0046AD96 /* SystemConfiguration.framework */; }; + 292500B41BB43A650046AD96 /* AVVenue.m in Sources */ = {isa = PBXBuildFile; fileRef = 292500B31BB43A650046AD96 /* AVVenue.m */; settings = {ASSET_TAGS = (); }; }; + 2925016B1BB6410C0046AD96 /* Location.m in Sources */ = {isa = PBXBuildFile; fileRef = 2925016A1BB6410C0046AD96 /* Location.m */; settings = {ASSET_TAGS = (); }; }; + 2925016E1BB647EA0046AD96 /* VenueCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 2925016D1BB647EA0046AD96 /* VenueCell.m */; settings = {ASSET_TAGS = (); }; }; + 292501711BB649400046AD96 /* Stats.m in Sources */ = {isa = PBXBuildFile; fileRef = 292501701BB649400046AD96 /* Stats.m */; settings = {ASSET_TAGS = (); }; }; + 520D00988A1AF4D3E80FDC41 /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E8255C1A1ACF5F9CB324D142 /* libPods.a */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 2925008A1BB42A2B0046AD96 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 292500651BB42A2B0046AD96 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 2925006C1BB42A2B0046AD96; + remoteInfo = AVRestKitFoursquareAPIapp; + }; + 292500951BB42A2B0046AD96 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 292500651BB42A2B0046AD96 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 2925006C1BB42A2B0046AD96; + remoteInfo = AVRestKitFoursquareAPIapp; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 2925006D1BB42A2B0046AD96 /* AVRestKitFoursquareAPIapp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AVRestKitFoursquareAPIapp.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 292500711BB42A2B0046AD96 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 292500731BB42A2B0046AD96 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; + 292500741BB42A2B0046AD96 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; + 292500761BB42A2B0046AD96 /* MasterViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MasterViewController.h; sourceTree = ""; }; + 292500771BB42A2B0046AD96 /* MasterViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MasterViewController.m; sourceTree = ""; }; + 292500791BB42A2B0046AD96 /* DetailViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DetailViewController.h; sourceTree = ""; }; + 2925007A1BB42A2B0046AD96 /* DetailViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DetailViewController.m; sourceTree = ""; }; + 2925007D1BB42A2B0046AD96 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 2925007F1BB42A2B0046AD96 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 292500821BB42A2B0046AD96 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 292500841BB42A2B0046AD96 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 292500891BB42A2B0046AD96 /* AVRestKitFoursquareAPIappTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = AVRestKitFoursquareAPIappTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 2925008D1BB42A2B0046AD96 /* AVRestKitFoursquareAPIappTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AVRestKitFoursquareAPIappTests.m; sourceTree = ""; }; + 2925008F1BB42A2B0046AD96 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 292500941BB42A2B0046AD96 /* AVRestKitFoursquareAPIappUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = AVRestKitFoursquareAPIappUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 292500981BB42A2C0046AD96 /* AVRestKitFoursquareAPIappUITests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AVRestKitFoursquareAPIappUITests.m; sourceTree = ""; }; + 2925009A1BB42A2C0046AD96 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 292500A61BB436AF0046AD96 /* libRestKit.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libRestKit.a; path = "Pods/../build/Debug-iphoneos/libRestKit.a"; sourceTree = ""; }; + 292500A81BB436EE0046AD96 /* CFNetwork.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CFNetwork.framework; path = System/Library/Frameworks/CFNetwork.framework; sourceTree = SDKROOT; }; + 292500AA1BB4371D0046AD96 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; }; + 292500AB1BB4371D0046AD96 /* MobileCoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MobileCoreServices.framework; path = System/Library/Frameworks/MobileCoreServices.framework; sourceTree = SDKROOT; }; + 292500AC1BB4371D0046AD96 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; + 292500AD1BB4371D0046AD96 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; }; + 292500B21BB43A650046AD96 /* AVVenue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AVVenue.h; sourceTree = ""; }; + 292500B31BB43A650046AD96 /* AVVenue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AVVenue.m; sourceTree = ""; }; + 292501691BB6410C0046AD96 /* Location.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Location.h; sourceTree = ""; }; + 2925016A1BB6410C0046AD96 /* Location.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Location.m; sourceTree = ""; }; + 2925016C1BB647EA0046AD96 /* VenueCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VenueCell.h; sourceTree = ""; }; + 2925016D1BB647EA0046AD96 /* VenueCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VenueCell.m; sourceTree = ""; }; + 2925016F1BB649400046AD96 /* Stats.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Stats.h; sourceTree = ""; }; + 292501701BB649400046AD96 /* Stats.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Stats.m; sourceTree = ""; }; + 8D802DE2785FC413B8FA08B8 /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.release.xcconfig; path = "Pods/Target Support Files/Pods/Pods.release.xcconfig"; sourceTree = ""; }; + E670B424D98ECF32883C2062 /* Pods.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.debug.xcconfig; path = "Pods/Target Support Files/Pods/Pods.debug.xcconfig"; sourceTree = ""; }; + E8255C1A1ACF5F9CB324D142 /* libPods.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPods.a; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 2925006A1BB42A2B0046AD96 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 292500AE1BB4371D0046AD96 /* CoreData.framework in Frameworks */, + 292500AF1BB4371D0046AD96 /* MobileCoreServices.framework in Frameworks */, + 292500B01BB4371D0046AD96 /* Security.framework in Frameworks */, + 292500B11BB4371D0046AD96 /* SystemConfiguration.framework in Frameworks */, + 292500A91BB436EE0046AD96 /* CFNetwork.framework in Frameworks */, + 292500A71BB436AF0046AD96 /* libRestKit.a in Frameworks */, + 520D00988A1AF4D3E80FDC41 /* libPods.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 292500861BB42A2B0046AD96 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 292500911BB42A2B0046AD96 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 292500641BB42A2A0046AD96 = { + isa = PBXGroup; + children = ( + 2925006F1BB42A2B0046AD96 /* AVRestKitFoursquareAPIapp */, + 2925008C1BB42A2B0046AD96 /* AVRestKitFoursquareAPIappTests */, + 292500971BB42A2C0046AD96 /* AVRestKitFoursquareAPIappUITests */, + 2925006E1BB42A2B0046AD96 /* Products */, + D0D26AEA08620C7CAB475C35 /* Pods */, + EBD0E29FE910A52085A0933E /* Frameworks */, + ); + sourceTree = ""; + }; + 2925006E1BB42A2B0046AD96 /* Products */ = { + isa = PBXGroup; + children = ( + 2925006D1BB42A2B0046AD96 /* AVRestKitFoursquareAPIapp.app */, + 292500891BB42A2B0046AD96 /* AVRestKitFoursquareAPIappTests.xctest */, + 292500941BB42A2B0046AD96 /* AVRestKitFoursquareAPIappUITests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 2925006F1BB42A2B0046AD96 /* AVRestKitFoursquareAPIapp */ = { + isa = PBXGroup; + children = ( + 2925007C1BB42A2B0046AD96 /* Main.storyboard */, + 292500731BB42A2B0046AD96 /* AppDelegate.h */, + 292500741BB42A2B0046AD96 /* AppDelegate.m */, + 292500B21BB43A650046AD96 /* AVVenue.h */, + 292500B31BB43A650046AD96 /* AVVenue.m */, + 292501691BB6410C0046AD96 /* Location.h */, + 2925016A1BB6410C0046AD96 /* Location.m */, + 2925016F1BB649400046AD96 /* Stats.h */, + 292501701BB649400046AD96 /* Stats.m */, + 2925016C1BB647EA0046AD96 /* VenueCell.h */, + 2925016D1BB647EA0046AD96 /* VenueCell.m */, + 292500761BB42A2B0046AD96 /* MasterViewController.h */, + 292500771BB42A2B0046AD96 /* MasterViewController.m */, + 292500791BB42A2B0046AD96 /* DetailViewController.h */, + 2925007A1BB42A2B0046AD96 /* DetailViewController.m */, + 2925007F1BB42A2B0046AD96 /* Assets.xcassets */, + 292500811BB42A2B0046AD96 /* LaunchScreen.storyboard */, + 292500841BB42A2B0046AD96 /* Info.plist */, + 292500701BB42A2B0046AD96 /* Supporting Files */, + ); + path = AVRestKitFoursquareAPIapp; + sourceTree = ""; + }; + 292500701BB42A2B0046AD96 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 292500711BB42A2B0046AD96 /* main.m */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + 2925008C1BB42A2B0046AD96 /* AVRestKitFoursquareAPIappTests */ = { + isa = PBXGroup; + children = ( + 2925008D1BB42A2B0046AD96 /* AVRestKitFoursquareAPIappTests.m */, + 2925008F1BB42A2B0046AD96 /* Info.plist */, + ); + path = AVRestKitFoursquareAPIappTests; + sourceTree = ""; + }; + 292500971BB42A2C0046AD96 /* AVRestKitFoursquareAPIappUITests */ = { + isa = PBXGroup; + children = ( + 292500981BB42A2C0046AD96 /* AVRestKitFoursquareAPIappUITests.m */, + 2925009A1BB42A2C0046AD96 /* Info.plist */, + ); + path = AVRestKitFoursquareAPIappUITests; + sourceTree = ""; + }; + D0D26AEA08620C7CAB475C35 /* Pods */ = { + isa = PBXGroup; + children = ( + E670B424D98ECF32883C2062 /* Pods.debug.xcconfig */, + 8D802DE2785FC413B8FA08B8 /* Pods.release.xcconfig */, + ); + name = Pods; + sourceTree = ""; + }; + EBD0E29FE910A52085A0933E /* Frameworks */ = { + isa = PBXGroup; + children = ( + 292500AA1BB4371D0046AD96 /* CoreData.framework */, + 292500AB1BB4371D0046AD96 /* MobileCoreServices.framework */, + 292500AC1BB4371D0046AD96 /* Security.framework */, + 292500AD1BB4371D0046AD96 /* SystemConfiguration.framework */, + 292500A81BB436EE0046AD96 /* CFNetwork.framework */, + 292500A61BB436AF0046AD96 /* libRestKit.a */, + E8255C1A1ACF5F9CB324D142 /* libPods.a */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 2925006C1BB42A2B0046AD96 /* AVRestKitFoursquareAPIapp */ = { + isa = PBXNativeTarget; + buildConfigurationList = 2925009D1BB42A2C0046AD96 /* Build configuration list for PBXNativeTarget "AVRestKitFoursquareAPIapp" */; + buildPhases = ( + 760CCCC3F9292230EB2A2123 /* Check Pods Manifest.lock */, + 292500691BB42A2B0046AD96 /* Sources */, + 2925006A1BB42A2B0046AD96 /* Frameworks */, + 2925006B1BB42A2B0046AD96 /* Resources */, + 5AE4E960AEBCD0A0C25EC303 /* Copy Pods Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = AVRestKitFoursquareAPIapp; + productName = AVRestKitFoursquareAPIapp; + productReference = 2925006D1BB42A2B0046AD96 /* AVRestKitFoursquareAPIapp.app */; + productType = "com.apple.product-type.application"; + }; + 292500881BB42A2B0046AD96 /* AVRestKitFoursquareAPIappTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 292500A01BB42A2C0046AD96 /* Build configuration list for PBXNativeTarget "AVRestKitFoursquareAPIappTests" */; + buildPhases = ( + 292500851BB42A2B0046AD96 /* Sources */, + 292500861BB42A2B0046AD96 /* Frameworks */, + 292500871BB42A2B0046AD96 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 2925008B1BB42A2B0046AD96 /* PBXTargetDependency */, + ); + name = AVRestKitFoursquareAPIappTests; + productName = AVRestKitFoursquareAPIappTests; + productReference = 292500891BB42A2B0046AD96 /* AVRestKitFoursquareAPIappTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 292500931BB42A2B0046AD96 /* AVRestKitFoursquareAPIappUITests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 292500A31BB42A2C0046AD96 /* Build configuration list for PBXNativeTarget "AVRestKitFoursquareAPIappUITests" */; + buildPhases = ( + 292500901BB42A2B0046AD96 /* Sources */, + 292500911BB42A2B0046AD96 /* Frameworks */, + 292500921BB42A2B0046AD96 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 292500961BB42A2B0046AD96 /* PBXTargetDependency */, + ); + name = AVRestKitFoursquareAPIappUITests; + productName = AVRestKitFoursquareAPIappUITests; + productReference = 292500941BB42A2B0046AD96 /* AVRestKitFoursquareAPIappUITests.xctest */; + productType = "com.apple.product-type.bundle.ui-testing"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 292500651BB42A2B0046AD96 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0700; + ORGANIZATIONNAME = "Ayuna Vogel"; + TargetAttributes = { + 2925006C1BB42A2B0046AD96 = { + CreatedOnToolsVersion = 7.0; + DevelopmentTeam = N48NM3R37Q; + }; + 292500881BB42A2B0046AD96 = { + CreatedOnToolsVersion = 7.0; + DevelopmentTeam = N48NM3R37Q; + TestTargetID = 2925006C1BB42A2B0046AD96; + }; + 292500931BB42A2B0046AD96 = { + CreatedOnToolsVersion = 7.0; + DevelopmentTeam = N48NM3R37Q; + TestTargetID = 2925006C1BB42A2B0046AD96; + }; + }; + }; + buildConfigurationList = 292500681BB42A2B0046AD96 /* Build configuration list for PBXProject "AVRestKitFoursquareAPIapp" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 292500641BB42A2A0046AD96; + productRefGroup = 2925006E1BB42A2B0046AD96 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 2925006C1BB42A2B0046AD96 /* AVRestKitFoursquareAPIapp */, + 292500881BB42A2B0046AD96 /* AVRestKitFoursquareAPIappTests */, + 292500931BB42A2B0046AD96 /* AVRestKitFoursquareAPIappUITests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 2925006B1BB42A2B0046AD96 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 292500831BB42A2B0046AD96 /* LaunchScreen.storyboard in Resources */, + 292500801BB42A2B0046AD96 /* Assets.xcassets in Resources */, + 2925007E1BB42A2B0046AD96 /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 292500871BB42A2B0046AD96 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 292500921BB42A2B0046AD96 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 5AE4E960AEBCD0A0C25EC303 /* Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Copy Pods Resources"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; + 760CCCC3F9292230EB2A2123 /* Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Check Pods Manifest.lock"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 292500691BB42A2B0046AD96 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 292500B41BB43A650046AD96 /* AVVenue.m in Sources */, + 292501711BB649400046AD96 /* Stats.m in Sources */, + 292500751BB42A2B0046AD96 /* AppDelegate.m in Sources */, + 292500781BB42A2B0046AD96 /* MasterViewController.m in Sources */, + 292500721BB42A2B0046AD96 /* main.m in Sources */, + 2925016B1BB6410C0046AD96 /* Location.m in Sources */, + 2925007B1BB42A2B0046AD96 /* DetailViewController.m in Sources */, + 2925016E1BB647EA0046AD96 /* VenueCell.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 292500851BB42A2B0046AD96 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 2925008E1BB42A2B0046AD96 /* AVRestKitFoursquareAPIappTests.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 292500901BB42A2B0046AD96 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 292500991BB42A2C0046AD96 /* AVRestKitFoursquareAPIappUITests.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 2925008B1BB42A2B0046AD96 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 2925006C1BB42A2B0046AD96 /* AVRestKitFoursquareAPIapp */; + targetProxy = 2925008A1BB42A2B0046AD96 /* PBXContainerItemProxy */; + }; + 292500961BB42A2B0046AD96 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 2925006C1BB42A2B0046AD96 /* AVRestKitFoursquareAPIapp */; + targetProxy = 292500951BB42A2B0046AD96 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 2925007C1BB42A2B0046AD96 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 2925007D1BB42A2B0046AD96 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 292500811BB42A2B0046AD96 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 292500821BB42A2B0046AD96 /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 2925009B1BB42A2C0046AD96 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + }; + name = Debug; + }; + 2925009C1BB42A2C0046AD96 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 2925009E1BB42A2C0046AD96 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = E670B424D98ECF32883C2062 /* Pods.debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + INFOPLIST_FILE = AVRestKitFoursquareAPIapp/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/build/Debug-iphoneos", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.ayunavogel.AVRestKitFoursquareAPIapp; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 2925009F1BB42A2C0046AD96 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 8D802DE2785FC413B8FA08B8 /* Pods.release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + INFOPLIST_FILE = AVRestKitFoursquareAPIapp/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/build/Debug-iphoneos", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.ayunavogel.AVRestKitFoursquareAPIapp; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; + 292500A11BB42A2C0046AD96 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + INFOPLIST_FILE = AVRestKitFoursquareAPIappTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.ayunavogel.AVRestKitFoursquareAPIappTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/AVRestKitFoursquareAPIapp.app/AVRestKitFoursquareAPIapp"; + }; + name = Debug; + }; + 292500A21BB42A2C0046AD96 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + INFOPLIST_FILE = AVRestKitFoursquareAPIappTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.ayunavogel.AVRestKitFoursquareAPIappTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/AVRestKitFoursquareAPIapp.app/AVRestKitFoursquareAPIapp"; + }; + name = Release; + }; + 292500A41BB42A2C0046AD96 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + INFOPLIST_FILE = AVRestKitFoursquareAPIappUITests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.ayunavogel.AVRestKitFoursquareAPIappUITests; + PRODUCT_NAME = "$(TARGET_NAME)"; + TEST_TARGET_NAME = AVRestKitFoursquareAPIapp; + USES_XCTRUNNER = YES; + }; + name = Debug; + }; + 292500A51BB42A2C0046AD96 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + INFOPLIST_FILE = AVRestKitFoursquareAPIappUITests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.ayunavogel.AVRestKitFoursquareAPIappUITests; + PRODUCT_NAME = "$(TARGET_NAME)"; + TEST_TARGET_NAME = AVRestKitFoursquareAPIapp; + USES_XCTRUNNER = YES; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 292500681BB42A2B0046AD96 /* Build configuration list for PBXProject "AVRestKitFoursquareAPIapp" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 2925009B1BB42A2C0046AD96 /* Debug */, + 2925009C1BB42A2C0046AD96 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 2925009D1BB42A2C0046AD96 /* Build configuration list for PBXNativeTarget "AVRestKitFoursquareAPIapp" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 2925009E1BB42A2C0046AD96 /* Debug */, + 2925009F1BB42A2C0046AD96 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 292500A01BB42A2C0046AD96 /* Build configuration list for PBXNativeTarget "AVRestKitFoursquareAPIappTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 292500A11BB42A2C0046AD96 /* Debug */, + 292500A21BB42A2C0046AD96 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 292500A31BB42A2C0046AD96 /* Build configuration list for PBXNativeTarget "AVRestKitFoursquareAPIappUITests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 292500A41BB42A2C0046AD96 /* Debug */, + 292500A51BB42A2C0046AD96 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 292500651BB42A2B0046AD96 /* Project object */; +} diff --git a/AVRestKitFoursquareAPIapp.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/AVRestKitFoursquareAPIapp.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..40adfec --- /dev/null +++ b/AVRestKitFoursquareAPIapp.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/AVRestKitFoursquareAPIapp.xcworkspace/contents.xcworkspacedata b/AVRestKitFoursquareAPIapp.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..5fbcd1b --- /dev/null +++ b/AVRestKitFoursquareAPIapp.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/AVRestKitFoursquareAPIapp/AVVenue.h b/AVRestKitFoursquareAPIapp/AVVenue.h new file mode 100644 index 0000000..6fd298f --- /dev/null +++ b/AVRestKitFoursquareAPIapp/AVVenue.h @@ -0,0 +1,20 @@ +// +// AVVenue.h +// AVRestKitFoursquareAPIapp +// +// Created by Ayuna Vogel on 9/24/15. +// Copyright © 2015 Ayuna Vogel. All rights reserved. +// + +#import +#import "Location.h" +@class Stats; + +@interface AVVenue : NSObject + +@property (nonatomic, strong) NSString *name; + +@property (nonatomic, strong) Location *location; +@property (strong, nonatomic) Stats *stats; + +@end diff --git a/AVRestKitFoursquareAPIapp/AVVenue.m b/AVRestKitFoursquareAPIapp/AVVenue.m new file mode 100644 index 0000000..07473e8 --- /dev/null +++ b/AVRestKitFoursquareAPIapp/AVVenue.m @@ -0,0 +1,13 @@ +// +// AVVenue.m +// AVRestKitFoursquareAPIapp +// +// Created by Ayuna Vogel on 9/24/15. +// Copyright © 2015 Ayuna Vogel. All rights reserved. +// + +#import "AVVenue.h" + +@implementation AVVenue + +@end diff --git a/AVRestKitFoursquareAPIapp/AppDelegate.h b/AVRestKitFoursquareAPIapp/AppDelegate.h new file mode 100644 index 0000000..28549e5 --- /dev/null +++ b/AVRestKitFoursquareAPIapp/AppDelegate.h @@ -0,0 +1,17 @@ +// +// AppDelegate.h +// AVRestKitFoursquareAPIapp +// +// Created by Ayuna Vogel on 9/24/15. +// Copyright © 2015 Ayuna Vogel. All rights reserved. +// + +#import + +@interface AppDelegate : UIResponder + +@property (strong, nonatomic) UIWindow *window; + + +@end + diff --git a/AVRestKitFoursquareAPIapp/AppDelegate.m b/AVRestKitFoursquareAPIapp/AppDelegate.m new file mode 100644 index 0000000..c47a26f --- /dev/null +++ b/AVRestKitFoursquareAPIapp/AppDelegate.m @@ -0,0 +1,81 @@ +// +// AppDelegate.m +// AVRestKitFoursquareAPIapp +// +// Created by Ayuna Vogel on 9/24/15. +// Copyright © 2015 Ayuna Vogel. All rights reserved. +// + +#import "AppDelegate.h" +#import "DetailViewController.h" +#import +#import +#import "DetailViewController.h" +#import "MasterViewController.h" + + +@interface AppDelegate () + +@end + +@implementation AppDelegate + + +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + + // Override point for customization after application launch. + UISplitViewController *splitViewController = (UISplitViewController *)self.window.rootViewController; + UINavigationController *navigationController = [splitViewController.viewControllers lastObject]; + navigationController.topViewController.navigationItem.leftBarButtonItem = splitViewController.displayModeButtonItem; + splitViewController.delegate = self; + + [GMSServices provideAPIKey:@"AIzaSyB7c8Iybgg1kzs9CdYLLjk44eExVUCcyKY"]; + + + MasterViewController *firstVC = [[MasterViewController alloc] init]; + DetailViewController* secondVC = [[DetailViewController alloc] init]; + + UISplitViewController* splitVC = [[UISplitViewController alloc] init]; + splitVC.viewControllers = [NSArray arrayWithObjects:firstVC, secondVC, nil]; + + self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; + self.window.rootViewController = splitVC; + [self.window makeKeyAndVisible]; + + return YES; +} + +- (void)applicationWillResignActive:(UIApplication *)application { + // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. + // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. +} + +- (void)applicationDidEnterBackground:(UIApplication *)application { + // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. + // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. +} + +- (void)applicationWillEnterForeground:(UIApplication *)application { + // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. +} + +- (void)applicationDidBecomeActive:(UIApplication *)application { + // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. +} + +- (void)applicationWillTerminate:(UIApplication *)application { + // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. +} + +#pragma mark - Split view + +- (BOOL)splitViewController:(UISplitViewController *)splitViewController collapseSecondaryViewController:(UIViewController *)secondaryViewController ontoPrimaryViewController:(UIViewController *)primaryViewController { + if ([secondaryViewController isKindOfClass:[UINavigationController class]] && [[(UINavigationController *)secondaryViewController topViewController] isKindOfClass:[DetailViewController class]] && ([(DetailViewController *)[(UINavigationController *)secondaryViewController topViewController] detailItem] == nil)) { + // Return YES to indicate that we have handled the collapse by doing nothing; the secondary controller will be discarded. + return YES; + } else { + return NO; + } +} + +@end diff --git a/AVRestKitFoursquareAPIapp/Assets.xcassets/AppIcon.appiconset/Contents.json b/AVRestKitFoursquareAPIapp/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..118c98f --- /dev/null +++ b/AVRestKitFoursquareAPIapp/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,38 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/AVRestKitFoursquareAPIapp/Base.lproj/LaunchScreen.storyboard b/AVRestKitFoursquareAPIapp/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..2e721e1 --- /dev/null +++ b/AVRestKitFoursquareAPIapp/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/AVRestKitFoursquareAPIapp/Base.lproj/Main.storyboard b/AVRestKitFoursquareAPIapp/Base.lproj/Main.storyboard new file mode 100644 index 0000000..0d6594f --- /dev/null +++ b/AVRestKitFoursquareAPIapp/Base.lproj/Main.storyboard @@ -0,0 +1,162 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/AVRestKitFoursquareAPIapp/DetailViewController.h b/AVRestKitFoursquareAPIapp/DetailViewController.h new file mode 100644 index 0000000..14af0b0 --- /dev/null +++ b/AVRestKitFoursquareAPIapp/DetailViewController.h @@ -0,0 +1,17 @@ +// +// DetailViewController.h +// AVRestKitFoursquareAPIapp +// +// Created by Ayuna Vogel on 9/24/15. +// Copyright © 2015 Ayuna Vogel. All rights reserved. +// + +#import + +@interface DetailViewController : UIViewController + +@property (strong, nonatomic) id detailItem; +@property (weak, nonatomic) IBOutlet UILabel *detailDescriptionLabel; + +@end + diff --git a/AVRestKitFoursquareAPIapp/DetailViewController.m b/AVRestKitFoursquareAPIapp/DetailViewController.m new file mode 100644 index 0000000..73e6e89 --- /dev/null +++ b/AVRestKitFoursquareAPIapp/DetailViewController.m @@ -0,0 +1,59 @@ +// +// DetailViewController.m +// AVRestKitFoursquareAPIapp +// +// Created by Ayuna Vogel on 9/24/15. +// Copyright © 2015 Ayuna Vogel. All rights reserved. +// + +#import "DetailViewController.h" +#import + + +@interface DetailViewController () + +@property (strong, nonatomic) GMSMapView *mapView; + +@end + +@implementation DetailViewController + +#pragma mark - Managing the detail item + +- (void)setDetailItem:(id)newDetailItem { + if (_detailItem != newDetailItem) { + _detailItem = newDetailItem; + + // Update the view. + [self configureView]; + } +} + +- (void)configureView { + // Update the user interface for the detail item. +// if (self.detailItem) { +// self.detailDescriptionLabel.text = [self.detailItem description]; +// } +} + +- (void)viewDidLoad { + [super viewDidLoad]; + + //self.mapView = [GMSMapView mapWithFrame:self.view.bounds camera:camera]; + self.mapView.mapType = kGMSTypeNormal; + self.mapView.myLocationEnabled = YES; + self.mapView.settings.compassButton = YES; + self.mapView.settings.myLocationButton = YES; + + + [self.view addSubview:self.mapView]; + + [self configureView]; +} + +- (void)didReceiveMemoryWarning { + [super didReceiveMemoryWarning]; + // Dispose of any resources that can be recreated. +} + +@end diff --git a/AVRestKitFoursquareAPIapp/Info.plist b/AVRestKitFoursquareAPIapp/Info.plist new file mode 100644 index 0000000..e214702 --- /dev/null +++ b/AVRestKitFoursquareAPIapp/Info.plist @@ -0,0 +1,50 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UIStatusBarTintParameters + + UINavigationBar + + Style + UIBarStyleDefault + Translucent + + + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/AVRestKitFoursquareAPIapp/Location.h b/AVRestKitFoursquareAPIapp/Location.h new file mode 100644 index 0000000..9020c59 --- /dev/null +++ b/AVRestKitFoursquareAPIapp/Location.h @@ -0,0 +1,23 @@ +// +// Location.h +// AVRestKitFoursquareAPIapp +// +// Created by Ayuna Vogel on 9/25/15. +// Copyright © 2015 Ayuna Vogel. All rights reserved. +// + +#import + +@interface Location : NSObject + +@property (nonatomic, strong) NSString *address; +@property (nonatomic, strong) NSString *city; +@property (nonatomic, strong) NSString *country; +@property (nonatomic, strong) NSString *crossStreet; +@property (nonatomic, strong) NSString *postalCode; +@property (nonatomic, strong) NSString *state; +@property (nonatomic, strong) NSNumber *distance; +@property (nonatomic, strong) NSNumber *lat; +@property (nonatomic, strong) NSNumber *lng; + +@end diff --git a/AVRestKitFoursquareAPIapp/Location.m b/AVRestKitFoursquareAPIapp/Location.m new file mode 100644 index 0000000..c4178c6 --- /dev/null +++ b/AVRestKitFoursquareAPIapp/Location.m @@ -0,0 +1,13 @@ +// +// Location.m +// AVRestKitFoursquareAPIapp +// +// Created by Ayuna Vogel on 9/25/15. +// Copyright © 2015 Ayuna Vogel. All rights reserved. +// + +#import "Location.h" + +@implementation Location + +@end diff --git a/AVRestKitFoursquareAPIapp/MasterViewController.h b/AVRestKitFoursquareAPIapp/MasterViewController.h new file mode 100644 index 0000000..8f4e415 --- /dev/null +++ b/AVRestKitFoursquareAPIapp/MasterViewController.h @@ -0,0 +1,19 @@ +// +// MasterViewController.h +// AVRestKitFoursquareAPIapp +// +// Created by Ayuna Vogel on 9/24/15. +// Copyright © 2015 Ayuna Vogel. All rights reserved. +// + +#import + +@class DetailViewController; + +@interface MasterViewController : UITableViewController + +@property (strong, nonatomic) DetailViewController *detailViewController; + + +@end + diff --git a/AVRestKitFoursquareAPIapp/MasterViewController.m b/AVRestKitFoursquareAPIapp/MasterViewController.m new file mode 100644 index 0000000..3371fe4 --- /dev/null +++ b/AVRestKitFoursquareAPIapp/MasterViewController.m @@ -0,0 +1,166 @@ +// +// MasterViewController.m +// AVRestKitFoursquareAPIapp +// +// Created by Ayuna Vogel on 9/24/15. +// Copyright © 2015 Ayuna Vogel. All rights reserved. +// + +#import "MasterViewController.h" +#import "DetailViewController.h" +#define kCLIENTID @"0LVI5VDRAAKPXMXD0PT0FZY4UYF2AMMHEZURSB125LOZB2SH" +#define kCLIENTSECRET @"VZCXZA3UWL510YPX5FEJAGZTRZSZBKQ45JI4YOLW10DAWYCU" +#import +#import "AVVenue.h" +#import "Location.h" +#import "VenueCell.h" +#import "Stats.h" + +@interface MasterViewController () + +@property (nonatomic, strong) NSArray *venues; +@property NSMutableArray *objects; + +@end + +@implementation MasterViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + // Do any additional setup after loading the view, typically from a nib. + self.navigationItem.leftBarButtonItem = self.editButtonItem; + + UIBarButtonItem *addButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(insertNewObject:)]; + self.navigationItem.rightBarButtonItem = addButton; + self.detailViewController = (DetailViewController *)[[self.splitViewController.viewControllers lastObject] topViewController]; + + [self configureRestKit]; + [self loadVenues]; +} + +- (void)configureRestKit { + // initialize AFNetworking HTTPClient + NSURL *baseURL = [NSURL URLWithString:@"https://api.foursquare.com"]; + AFHTTPClient *client = [[AFHTTPClient alloc] initWithBaseURL:baseURL]; + + // initialize RestKit + RKObjectManager *objectManager = [[RKObjectManager alloc] initWithHTTPClient:client]; + + // setup object mappings + RKObjectMapping *venueMapping = [RKObjectMapping mappingForClass:[AVVenue class]]; + [venueMapping addAttributeMappingsFromArray:@[@"name"]]; + + // register mappings with the provider using a response descriptor + RKResponseDescriptor *responseDescriptor = + [RKResponseDescriptor responseDescriptorWithMapping:venueMapping + method:RKRequestMethodGET + pathPattern:@"/v2/venues/search" + keyPath:@"response.venues" + statusCodes:[NSIndexSet indexSetWithIndex:200]]; + + [objectManager addResponseDescriptor:responseDescriptor]; + + // define location object mapping + RKObjectMapping *locationMapping = [RKObjectMapping mappingForClass:[Location class]]; + [locationMapping addAttributeMappingsFromArray:@[@"address", @"city", @"country", @"crossStreet", @"postalCode", @"state", @"distance", @"lat", @"lng"]]; + + // define relationship mapping + [venueMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"location" toKeyPath:@"location" withMapping:locationMapping]]; + + RKObjectMapping *statsMapping = [RKObjectMapping mappingForClass:[Stats class]]; + [statsMapping addAttributeMappingsFromDictionary:@{@"checkinsCount": @"checkins", @"tipsCount": @"tips", @"usersCount": @"users"}]; + + [venueMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"stats" toKeyPath:@"stats" withMapping:statsMapping]]; +} + +- (void)loadVenues { + NSString *latLon = @"40.762641, -73.918791"; // @"37.33,-122.03"; approximate latLon of the Apple headquarters + NSString *clientID = kCLIENTID; + NSString *clientSecret = kCLIENTSECRET; + + NSDictionary *queryParams = @{@"ll" : latLon, + @"client_id" : clientID, + @"client_secret" : clientSecret, + @"categoryId" : @"4bf58dd8d48988d1e0931735", + @"v" : @"20140118"}; + + [[RKObjectManager sharedManager] getObjectsAtPath:@"/v2/venues/search" + parameters:queryParams + success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) { + _venues = mappingResult.array; + [self.tableView reloadData]; + } + failure:^(RKObjectRequestOperation *operation, NSError *error) { + NSLog(@"What do you mean by 'there is no coffee?': %@", error); + }]; +} + +- (void)viewWillAppear:(BOOL)animated { + self.clearsSelectionOnViewWillAppear = self.splitViewController.isCollapsed; + [super viewWillAppear:animated]; +} + +- (void)didReceiveMemoryWarning { + [super didReceiveMemoryWarning]; + // Dispose of any resources that can be recreated. +} + +- (void)insertNewObject:(id)sender { + if (!self.objects) { + self.objects = [[NSMutableArray alloc] init]; + } + [self.objects insertObject:[NSDate date] atIndex:0]; + NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0]; + [self.tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic]; +} + +#pragma mark - Segues + +- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { + if ([[segue identifier] isEqualToString:@"showDetail"]) { + NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow]; + NSDate *object = self.objects[indexPath.row]; + DetailViewController *controller = (DetailViewController *)[[segue destinationViewController] topViewController]; + [controller setDetailItem:object]; + controller.navigationItem.leftBarButtonItem = self.splitViewController.displayModeButtonItem; + controller.navigationItem.leftItemsSupplementBackButton = YES; + } +} + +#pragma mark - Table View + +- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { + return 1; +} + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + //return self.objects.count; + return _venues.count; +} + +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { + VenueCell *cell = [tableView dequeueReusableCellWithIdentifier:@"VenueCell" forIndexPath:indexPath]; + + AVVenue *venue = _venues[indexPath.row]; + cell.nameLabel.text = venue.name; + cell.distanceLabel.text = [NSString stringWithFormat:@"%.0fm", venue.location.distance.floatValue]; + cell.checkinsLabel.text = [NSString stringWithFormat:@"%d checkins", venue.stats.checkins.intValue]; return cell; +} + +# pragma mark - other Table View methods + +- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath { + // Return NO if you do not want the specified item to be editable. + return YES; +} + +- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { + if (editingStyle == UITableViewCellEditingStyleDelete) { + [self.objects removeObjectAtIndex:indexPath.row]; + [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade]; + } else if (editingStyle == UITableViewCellEditingStyleInsert) { + // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view. + } +} + +@end diff --git a/AVRestKitFoursquareAPIapp/Stats.h b/AVRestKitFoursquareAPIapp/Stats.h new file mode 100644 index 0000000..04d2f95 --- /dev/null +++ b/AVRestKitFoursquareAPIapp/Stats.h @@ -0,0 +1,17 @@ +// +// Stats.h +// AVRestKitFoursquareAPIapp +// +// Created by Ayuna Vogel on 9/25/15. +// Copyright © 2015 Ayuna Vogel. All rights reserved. +// + +#import + +@interface Stats : NSObject + +@property (nonatomic, strong) NSNumber *checkins; +@property (nonatomic, strong) NSNumber *tips; +@property (nonatomic, strong) NSNumber *users; + +@end diff --git a/AVRestKitFoursquareAPIapp/Stats.m b/AVRestKitFoursquareAPIapp/Stats.m new file mode 100644 index 0000000..238fc0f --- /dev/null +++ b/AVRestKitFoursquareAPIapp/Stats.m @@ -0,0 +1,13 @@ +// +// Stats.m +// AVRestKitFoursquareAPIapp +// +// Created by Ayuna Vogel on 9/25/15. +// Copyright © 2015 Ayuna Vogel. All rights reserved. +// + +#import "Stats.h" + +@implementation Stats + +@end diff --git a/AVRestKitFoursquareAPIapp/VenueCell.h b/AVRestKitFoursquareAPIapp/VenueCell.h new file mode 100644 index 0000000..1113baf --- /dev/null +++ b/AVRestKitFoursquareAPIapp/VenueCell.h @@ -0,0 +1,17 @@ +// +// VenueCell.h +// AVRestKitFoursquareAPIapp +// +// Created by Ayuna Vogel on 9/25/15. +// Copyright © 2015 Ayuna Vogel. All rights reserved. +// + +#import + +@interface VenueCell : UITableViewCell + +@property (nonatomic, weak) IBOutlet UILabel *nameLabel; +@property (nonatomic, weak) IBOutlet UILabel *distanceLabel; +@property (nonatomic, weak) IBOutlet UILabel *checkinsLabel; + +@end diff --git a/AVRestKitFoursquareAPIapp/VenueCell.m b/AVRestKitFoursquareAPIapp/VenueCell.m new file mode 100644 index 0000000..5a7fc1b --- /dev/null +++ b/AVRestKitFoursquareAPIapp/VenueCell.m @@ -0,0 +1,14 @@ +// +// VenueCell.m +// AVRestKitFoursquareAPIapp +// +// Created by Ayuna Vogel on 9/25/15. +// Copyright © 2015 Ayuna Vogel. All rights reserved. +// + +#import "VenueCell.h" + +@implementation VenueCell + + +@end diff --git a/AVRestKitFoursquareAPIapp/main.m b/AVRestKitFoursquareAPIapp/main.m new file mode 100644 index 0000000..9c5787f --- /dev/null +++ b/AVRestKitFoursquareAPIapp/main.m @@ -0,0 +1,16 @@ +// +// main.m +// AVRestKitFoursquareAPIapp +// +// Created by Ayuna Vogel on 9/24/15. +// Copyright © 2015 Ayuna Vogel. All rights reserved. +// + +#import +#import "AppDelegate.h" + +int main(int argc, char * argv[]) { + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); + } +} diff --git a/AVRestKitFoursquareAPIappTests/AVRestKitFoursquareAPIappTests.m b/AVRestKitFoursquareAPIappTests/AVRestKitFoursquareAPIappTests.m new file mode 100644 index 0000000..535c424 --- /dev/null +++ b/AVRestKitFoursquareAPIappTests/AVRestKitFoursquareAPIappTests.m @@ -0,0 +1,39 @@ +// +// AVRestKitFoursquareAPIappTests.m +// AVRestKitFoursquareAPIappTests +// +// Created by Ayuna Vogel on 9/24/15. +// Copyright © 2015 Ayuna Vogel. All rights reserved. +// + +#import + +@interface AVRestKitFoursquareAPIappTests : XCTestCase + +@end + +@implementation AVRestKitFoursquareAPIappTests + +- (void)setUp { + [super setUp]; + // Put setup code here. This method is called before the invocation of each test method in the class. +} + +- (void)tearDown { + // Put teardown code here. This method is called after the invocation of each test method in the class. + [super tearDown]; +} + +- (void)testExample { + // This is an example of a functional test case. + // Use XCTAssert and related functions to verify your tests produce the correct results. +} + +- (void)testPerformanceExample { + // This is an example of a performance test case. + [self measureBlock:^{ + // Put the code you want to measure the time of here. + }]; +} + +@end diff --git a/AVRestKitFoursquareAPIappTests/Info.plist b/AVRestKitFoursquareAPIappTests/Info.plist new file mode 100644 index 0000000..ba72822 --- /dev/null +++ b/AVRestKitFoursquareAPIappTests/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + + diff --git a/AVRestKitFoursquareAPIappUITests/AVRestKitFoursquareAPIappUITests.m b/AVRestKitFoursquareAPIappUITests/AVRestKitFoursquareAPIappUITests.m new file mode 100644 index 0000000..88af0be --- /dev/null +++ b/AVRestKitFoursquareAPIappUITests/AVRestKitFoursquareAPIappUITests.m @@ -0,0 +1,40 @@ +// +// AVRestKitFoursquareAPIappUITests.m +// AVRestKitFoursquareAPIappUITests +// +// Created by Ayuna Vogel on 9/24/15. +// Copyright © 2015 Ayuna Vogel. All rights reserved. +// + +#import + +@interface AVRestKitFoursquareAPIappUITests : XCTestCase + +@end + +@implementation AVRestKitFoursquareAPIappUITests + +- (void)setUp { + [super setUp]; + + // Put setup code here. This method is called before the invocation of each test method in the class. + + // In UI tests it is usually best to stop immediately when a failure occurs. + self.continueAfterFailure = NO; + // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method. + [[[XCUIApplication alloc] init] launch]; + + // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. +} + +- (void)tearDown { + // Put teardown code here. This method is called after the invocation of each test method in the class. + [super tearDown]; +} + +- (void)testExample { + // Use recording to get started writing UI tests. + // Use XCTAssert and related functions to verify your tests produce the correct results. +} + +@end diff --git a/AVRestKitFoursquareAPIappUITests/Info.plist b/AVRestKitFoursquareAPIappUITests/Info.plist new file mode 100644 index 0000000..ba72822 --- /dev/null +++ b/AVRestKitFoursquareAPIappUITests/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + + diff --git a/Podfile b/Podfile new file mode 100644 index 0000000..1e776a3 --- /dev/null +++ b/Podfile @@ -0,0 +1,2 @@ +pod 'RestKit', '~> 0.25' +pod 'GoogleMaps', '~> 1.10' \ No newline at end of file diff --git a/Podfile.lock b/Podfile.lock new file mode 100644 index 0000000..709a18b --- /dev/null +++ b/Podfile.lock @@ -0,0 +1,42 @@ +PODS: + - AFNetworking (1.3.4) + - GoogleMaps (1.10.3) + - ISO8601DateFormatterValueTransformer (0.6.1): + - RKValueTransformers (~> 1.1.0) + - RestKit (0.25.0): + - RestKit/Core (= 0.25.0) + - RestKit/Core (0.25.0): + - RestKit/CoreData + - RestKit/Network + - RestKit/ObjectMapping + - RestKit/CoreData (0.25.0): + - RestKit/ObjectMapping + - RestKit/Network (0.25.0): + - AFNetworking (~> 1.3.0) + - RestKit/ObjectMapping + - RestKit/Support + - SOCKit + - RestKit/ObjectMapping (0.25.0): + - ISO8601DateFormatterValueTransformer (~> 0.6.1) + - RestKit/Support + - RKValueTransformers (~> 1.1.0) + - RestKit/Support (0.25.0): + - TransitionKit (~> 2.1.0) + - RKValueTransformers (1.1.2) + - SOCKit (1.1) + - TransitionKit (2.1.1) + +DEPENDENCIES: + - GoogleMaps (~> 1.10) + - RestKit (~> 0.25) + +SPEC CHECKSUMS: + AFNetworking: cf8e418e16f0c9c7e5c3150d019a3c679d015018 + GoogleMaps: 945e4ac3b74bcca3ddada51df256eb7beddb474d + ISO8601DateFormatterValueTransformer: 52da467d6ec899d6aedda8e48280ac92e8ee97e6 + RestKit: a4fcaf3d4bb2c204679856a46d596160bf208095 + RKValueTransformers: 66ac5e4f077fdbe3496e792d89eeff4c3eb67701 + SOCKit: c7376ac262bea9115b8f749358f762522a47d392 + TransitionKit: 3a14b6acc7cf2d1dd3e454e24dbad1cfab9a1ef1 + +COCOAPODS: 0.38.2 diff --git a/Pods/AFNetworking/AFNetworking/AFHTTPClient.h b/Pods/AFNetworking/AFNetworking/AFHTTPClient.h new file mode 100644 index 0000000..3826b6f --- /dev/null +++ b/Pods/AFNetworking/AFNetworking/AFHTTPClient.h @@ -0,0 +1,641 @@ +// AFHTTPClient.h +// +// Copyright (c) 2011 Gowalla (http://gowalla.com/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "AFURLConnectionOperation.h" + +#import + +/** + `AFHTTPClient` captures the common patterns of communicating with an web application over HTTP. It encapsulates information like base URL, authorization credentials, and HTTP headers, and uses them to construct and manage the execution of HTTP request operations. + + ## Automatic Content Parsing + + Instances of `AFHTTPClient` may specify which types of requests it expects and should handle by registering HTTP operation classes for automatic parsing. Registered classes will determine whether they can handle a particular request, and then construct a request operation accordingly in `enqueueHTTPRequestOperationWithRequest:success:failure`. + + ## Subclassing Notes + + In most cases, one should create an `AFHTTPClient` subclass for each website or web application that your application communicates with. It is often useful, also, to define a class method that returns a singleton shared HTTP client in each subclass, that persists authentication credentials and other configuration across the entire application. + + ## Methods to Override + + To change the behavior of all url request construction for an `AFHTTPClient` subclass, override `requestWithMethod:path:parameters`. + + To change the behavior of all request operation construction for an `AFHTTPClient` subclass, override `HTTPRequestOperationWithRequest:success:failure`. + + ## Default Headers + + By default, `AFHTTPClient` sets the following HTTP headers: + + - `Accept-Language: (comma-delimited preferred languages), en-us;q=0.8` + - `User-Agent: (generated user agent)` + + You can override these HTTP headers or define new ones using `setDefaultHeader:value:`. + + ## URL Construction Using Relative Paths + + Both `-requestWithMethod:path:parameters:` and `-multipartFormRequestWithMethod:path:parameters:constructingBodyWithBlock:` construct URLs from the path relative to the `-baseURL`, using `NSURL +URLWithString:relativeToURL:`. Below are a few examples of how `baseURL` and relative paths interact: + + NSURL *baseURL = [NSURL URLWithString:@"http://example.com/v1/"]; + [NSURL URLWithString:@"foo" relativeToURL:baseURL]; // http://example.com/v1/foo + [NSURL URLWithString:@"foo?bar=baz" relativeToURL:baseURL]; // http://example.com/v1/foo?bar=baz + [NSURL URLWithString:@"/foo" relativeToURL:baseURL]; // http://example.com/foo + [NSURL URLWithString:@"foo/" relativeToURL:baseURL]; // http://example.com/v1/foo + [NSURL URLWithString:@"/foo/" relativeToURL:baseURL]; // http://example.com/foo/ + [NSURL URLWithString:@"http://example2.com/" relativeToURL:baseURL]; // http://example2.com/ + + Also important to note is that a trailing slash will be added to any `baseURL` without one, which would otherwise cause unexpected behavior when constructing URLs using paths without a leading slash. + + ## NSCoding / NSCopying Conformance + + `AFHTTPClient` conforms to the `NSCoding` and `NSCopying` protocols, allowing operations to be archived to disk, and copied in memory, respectively. There are a few minor caveats to keep in mind, however: + + - Archives and copies of HTTP clients will be initialized with an empty operation queue. + - NSCoding cannot serialize / deserialize block properties, so an archive of an HTTP client will not include any reachability callback block that may be set. + */ + +#ifdef _SYSTEMCONFIGURATION_H +typedef enum { + AFNetworkReachabilityStatusUnknown = -1, + AFNetworkReachabilityStatusNotReachable = 0, + AFNetworkReachabilityStatusReachableViaWWAN = 1, + AFNetworkReachabilityStatusReachableViaWiFi = 2, +} AFNetworkReachabilityStatus; +#else +#pragma message("SystemConfiguration framework not found in project, or not included in precompiled header. Network reachability functionality will not be available.") +#endif + +#ifndef __UTTYPE__ +#if __IPHONE_OS_VERSION_MIN_REQUIRED +#pragma message("MobileCoreServices framework not found in project, or not included in precompiled header. Automatic MIME type detection when uploading files in multipart requests will not be available.") +#else +#pragma message("CoreServices framework not found in project, or not included in precompiled header. Automatic MIME type detection when uploading files in multipart requests will not be available.") +#endif +#endif + +typedef enum { + AFFormURLParameterEncoding, + AFJSONParameterEncoding, + AFPropertyListParameterEncoding, +} AFHTTPClientParameterEncoding; + +@class AFHTTPRequestOperation; +@protocol AFMultipartFormData; + +@interface AFHTTPClient : NSObject + +///--------------------------------------- +/// @name Accessing HTTP Client Properties +///--------------------------------------- + +/** + The url used as the base for paths specified in methods such as `getPath:parameters:success:failure` + */ +@property (readonly, nonatomic, strong) NSURL *baseURL; + +/** + The string encoding used in constructing url requests. This is `NSUTF8StringEncoding` by default. + */ +@property (nonatomic, assign) NSStringEncoding stringEncoding; + +/** + The `AFHTTPClientParameterEncoding` value corresponding to how parameters are encoded into a request body for request methods other than `GET`, `HEAD` or `DELETE`. This is `AFFormURLParameterEncoding` by default. + + @warning Some nested parameter structures, such as a keyed array of hashes containing inconsistent keys (i.e. `@{@"": @[@{@"a" : @(1)}, @{@"b" : @(2)}]}`), cannot be unambiguously represented in query strings. It is strongly recommended that an unambiguous encoding, such as `AFJSONParameterEncoding`, is used when posting complicated or nondeterministic parameter structures. + */ +@property (nonatomic, assign) AFHTTPClientParameterEncoding parameterEncoding; + +/** + The operation queue which manages operations enqueued by the HTTP client. + */ +@property (readonly, nonatomic, strong) NSOperationQueue *operationQueue; + +/** + The reachability status from the device to the current `baseURL` of the `AFHTTPClient`. + + @warning This property requires the `SystemConfiguration` framework. Add it in the active target's "Link Binary With Library" build phase, and add `#import ` to the header prefix of the project (`Prefix.pch`). + */ +#ifdef _SYSTEMCONFIGURATION_H +@property (readonly, nonatomic, assign) AFNetworkReachabilityStatus networkReachabilityStatus; +#endif + +/** + Default SSL pinning mode for each `AFHTTPRequestOperation` created by `HTTPRequestOperationWithRequest:success:failure:`. + */ +@property (nonatomic, assign) AFURLConnectionOperationSSLPinningMode defaultSSLPinningMode; + +/** + Whether each `AFHTTPRequestOperation` created by `HTTPRequestOperationWithRequest:success:failure:` should accept an invalid SSL certificate. + + If `_AFNETWORKING_ALLOW_INVALID_SSL_CERTIFICATES_` is set, this property defaults to `YES` for backwards compatibility. Otherwise, this property defaults to `NO`. + */ +@property (nonatomic, assign) BOOL allowsInvalidSSLCertificate; + +///--------------------------------------------- +/// @name Creating and Initializing HTTP Clients +///--------------------------------------------- + +/** + Creates and initializes an `AFHTTPClient` object with the specified base URL. + + @param url The base URL for the HTTP client. This argument must not be `nil`. + + @return The newly-initialized HTTP client + */ ++ (instancetype)clientWithBaseURL:(NSURL *)url; + +/** + Initializes an `AFHTTPClient` object with the specified base URL. + + This is the designated initializer. + + @param url The base URL for the HTTP client. This argument must not be `nil`. + + @return The newly-initialized HTTP client + */ +- (id)initWithBaseURL:(NSURL *)url; + +///----------------------------------- +/// @name Managing Reachability Status +///----------------------------------- + +/** + Sets a callback to be executed when the network availability of the `baseURL` host changes. + + @param block A block object to be executed when the network availability of the `baseURL` host changes.. This block has no return value and takes a single argument which represents the various reachability states from the device to the `baseURL`. + + @warning This method requires the `SystemConfiguration` framework. Add it in the active target's "Link Binary With Library" build phase, and add `#import ` to the header prefix of the project (`Prefix.pch`). + */ +#ifdef _SYSTEMCONFIGURATION_H +- (void)setReachabilityStatusChangeBlock:(void (^)(AFNetworkReachabilityStatus status))block; +#endif + +///------------------------------- +/// @name Managing HTTP Operations +///------------------------------- + +/** + Attempts to register a subclass of `AFHTTPRequestOperation`, adding it to a chain to automatically generate request operations from a URL request. + + When `enqueueHTTPRequestOperationWithRequest:success:failure` is invoked, each registered class is consulted in turn to see if it can handle the specific request. The first class to return `YES` when sent a `canProcessRequest:` message is used to create an operation using `initWithURLRequest:` and do `setCompletionBlockWithSuccess:failure:`. There is no guarantee that all registered classes will be consulted. Classes are consulted in the reverse order of their registration. Attempting to register an already-registered class will move it to the top of the list. + + @param operationClass The subclass of `AFHTTPRequestOperation` to register + + @return `YES` if the registration is successful, `NO` otherwise. The only failure condition is if `operationClass` is not a subclass of `AFHTTPRequestOperation`. + */ +- (BOOL)registerHTTPOperationClass:(Class)operationClass; + +/** + Unregisters the specified subclass of `AFHTTPRequestOperation` from the chain of classes consulted when `-requestWithMethod:path:parameters` is called. + + @param operationClass The subclass of `AFHTTPRequestOperation` to register + */ +- (void)unregisterHTTPOperationClass:(Class)operationClass; + +///---------------------------------- +/// @name Managing HTTP Header Values +///---------------------------------- + +/** + Returns the value for the HTTP headers set in request objects created by the HTTP client. + + @param header The HTTP header to return the default value for + + @return The default value for the HTTP header, or `nil` if unspecified + */ +- (NSString *)defaultValueForHeader:(NSString *)header; + +/** + Sets the value for the HTTP headers set in request objects made by the HTTP client. If `nil`, removes the existing value for that header. + + @param header The HTTP header to set a default value for + @param value The value set as default for the specified header, or `nil + */ +- (void)setDefaultHeader:(NSString *)header + value:(NSString *)value; + +/** + Sets the "Authorization" HTTP header set in request objects made by the HTTP client to a basic authentication value with Base64-encoded username and password. This overwrites any existing value for this header. + + @param username The HTTP basic auth username + @param password The HTTP basic auth password + */ +- (void)setAuthorizationHeaderWithUsername:(NSString *)username + password:(NSString *)password; + +/** + Sets the "Authorization" HTTP header set in request objects made by the HTTP client to a token-based authentication value, such as an OAuth access token. This overwrites any existing value for this header. + + @param token The authentication token + */ +- (void)setAuthorizationHeaderWithToken:(NSString *)token; + + +/** + Clears any existing value for the "Authorization" HTTP header. + */ +- (void)clearAuthorizationHeader; + +///------------------------------- +/// @name Managing URL Credentials +///------------------------------- + +/** + Set the default URL credential to be set for request operations. + + @param credential The URL credential + */ +- (void)setDefaultCredential:(NSURLCredential *)credential; + +///------------------------------- +/// @name Creating Request Objects +///------------------------------- + +/** + Creates an `NSMutableURLRequest` object with the specified HTTP method and path. + + If the HTTP method is `GET`, `HEAD`, or `DELETE`, the parameters will be used to construct a url-encoded query string that is appended to the request's URL. Otherwise, the parameters will be encoded according to the value of the `parameterEncoding` property, and set as the request body. + + @param method The HTTP method for the request, such as `GET`, `POST`, `PUT`, or `DELETE`. This parameter must not be `nil`. + @param path The path to be appended to the HTTP client's base URL and used as the request URL. If `nil`, no path will be appended to the base URL. + @param parameters The parameters to be either set as a query string for `GET` requests, or the request HTTP body. + + @return An `NSMutableURLRequest` object + */ +- (NSMutableURLRequest *)requestWithMethod:(NSString *)method + path:(NSString *)path + parameters:(NSDictionary *)parameters; + +/** + Creates an `NSMutableURLRequest` object with the specified HTTP method and path, and constructs a `multipart/form-data` HTTP body, using the specified parameters and multipart form data block. See http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4.2 + + Multipart form requests are automatically streamed, reading files directly from disk along with in-memory data in a single HTTP body. The resulting `NSMutableURLRequest` object has an `HTTPBodyStream` property, so refrain from setting `HTTPBodyStream` or `HTTPBody` on this request object, as it will clear out the multipart form body stream. + + @param method The HTTP method for the request. This parameter must not be `GET` or `HEAD`, or `nil`. + @param path The path to be appended to the HTTP client's base URL and used as the request URL. + @param parameters The parameters to be encoded and set in the request HTTP body. + @param block A block that takes a single argument and appends data to the HTTP body. The block argument is an object adopting the `AFMultipartFormData` protocol. This can be used to upload files, encode HTTP body as JSON or XML, or specify multiple values for the same parameter, as one might for array values. + + @return An `NSMutableURLRequest` object + */ +- (NSMutableURLRequest *)multipartFormRequestWithMethod:(NSString *)method + path:(NSString *)path + parameters:(NSDictionary *)parameters + constructingBodyWithBlock:(void (^)(id formData))block; + +///------------------------------- +/// @name Creating HTTP Operations +///------------------------------- + +/** + Creates an `AFHTTPRequestOperation`. + + In order to determine what kind of operation is created, each registered subclass conforming to the `AFHTTPClient` protocol is consulted (in reverse order of when they were specified) to see if it can handle the specific request. The first class to return `YES` when sent a `canProcessRequest:` message is used to generate an operation using `HTTPRequestOperationWithRequest:success:failure:`. + + @param urlRequest The request object to be loaded asynchronously during execution of the operation. + @param success A block object to be executed when the request operation finishes successfully. This block has no return value and takes two arguments: the created request operation and the object created from the response data of request. + @param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes two arguments:, the created request operation and the `NSError` object describing the network or parsing error that occurred. + */ +- (AFHTTPRequestOperation *)HTTPRequestOperationWithRequest:(NSURLRequest *)urlRequest + success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success + failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure; + +///---------------------------------------- +/// @name Managing Enqueued HTTP Operations +///---------------------------------------- + +/** + Enqueues an `AFHTTPRequestOperation` to the HTTP client's operation queue. + + @param operation The HTTP request operation to be enqueued. + */ +- (void)enqueueHTTPRequestOperation:(AFHTTPRequestOperation *)operation; + +/** + Cancels all operations in the HTTP client's operation queue whose URLs match the specified HTTP method and path. + + This method only cancels `AFHTTPRequestOperations` whose request URL matches the HTTP client base URL with the path appended. For complete control over the lifecycle of enqueued operations, you can access the `operationQueue` property directly, which allows you to, for instance, cancel operations filtered by a predicate, or simply use `-cancelAllRequests`. Note that the operation queue may include non-HTTP operations, so be sure to check the type before attempting to directly introspect an operation's `request` property. + + @param method The HTTP method to match for the cancelled requests, such as `GET`, `POST`, `PUT`, or `DELETE`. If `nil`, all request operations with URLs matching the path will be cancelled. + @param path The path appended to the HTTP client base URL to match against the cancelled requests. If `nil`, no path will be appended to the base URL. + */ +- (void)cancelAllHTTPOperationsWithMethod:(NSString *)method path:(NSString *)path; + +///--------------------------------------- +/// @name Batching HTTP Request Operations +///--------------------------------------- + +/** + Creates and enqueues an `AFHTTPRequestOperation` to the HTTP client's operation queue for each specified request object into a batch. When each request operation finishes, the specified progress block is executed, until all of the request operations have finished, at which point the completion block also executes. + + Operations are created by passing the specified `NSURLRequest` objects in `requests`, using `-HTTPRequestOperationWithRequest:success:failure:`, with `nil` for both the `success` and `failure` parameters. + + @param urlRequests The `NSURLRequest` objects used to create and enqueue operations. + @param progressBlock A block object to be executed upon the completion of each request operation in the batch. This block has no return value and takes two arguments: the number of operations that have already finished execution, and the total number of operations. + @param completionBlock A block object to be executed upon the completion of all of the request operations in the batch. This block has no return value and takes a single argument: the batched request operations. + */ +- (void)enqueueBatchOfHTTPRequestOperationsWithRequests:(NSArray *)urlRequests + progressBlock:(void (^)(NSUInteger numberOfFinishedOperations, NSUInteger totalNumberOfOperations))progressBlock + completionBlock:(void (^)(NSArray *operations))completionBlock; + +/** + Enqueues the specified request operations into a batch. When each request operation finishes, the specified progress block is executed, until all of the request operations have finished, at which point the completion block also executes. + + @param operations The request operations used to be batched and enqueued. + @param progressBlock A block object to be executed upon the completion of each request operation in the batch. This block has no return value and takes two arguments: the number of operations that have already finished execution, and the total number of operations. + @param completionBlock A block object to be executed upon the completion of all of the request operations in the batch. This block has no return value and takes a single argument: the batched request operations. + */ +- (void)enqueueBatchOfHTTPRequestOperations:(NSArray *)operations + progressBlock:(void (^)(NSUInteger numberOfFinishedOperations, NSUInteger totalNumberOfOperations))progressBlock + completionBlock:(void (^)(NSArray *operations))completionBlock; + +///--------------------------- +/// @name Making HTTP Requests +///--------------------------- + +/** + Creates an `AFHTTPRequestOperation` with a `GET` request, and enqueues it to the HTTP client's operation queue. + + @param path The path to be appended to the HTTP client's base URL and used as the request URL. + @param parameters The parameters to be encoded and appended as the query string for the request URL. + @param success A block object to be executed when the request operation finishes successfully. This block has no return value and takes two arguments: the created request operation and the object created from the response data of request. + @param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes two arguments: the created request operation and the `NSError` object describing the network or parsing error that occurred. + + @see -HTTPRequestOperationWithRequest:success:failure: + */ +- (void)getPath:(NSString *)path + parameters:(NSDictionary *)parameters + success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success + failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure; + +/** + Creates an `AFHTTPRequestOperation` with a `POST` request, and enqueues it to the HTTP client's operation queue. + + @param path The path to be appended to the HTTP client's base URL and used as the request URL. + @param parameters The parameters to be encoded and set in the request HTTP body. + @param success A block object to be executed when the request operation finishes successfully. This block has no return value and takes two arguments: the created request operation and the object created from the response data of request. + @param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes two arguments: the created request operation and the `NSError` object describing the network or parsing error that occurred. + + @see -HTTPRequestOperationWithRequest:success:failure: + */ +- (void)postPath:(NSString *)path + parameters:(NSDictionary *)parameters + success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success + failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure; + +/** + Creates an `AFHTTPRequestOperation` with a `PUT` request, and enqueues it to the HTTP client's operation queue. + + @param path The path to be appended to the HTTP client's base URL and used as the request URL. + @param parameters The parameters to be encoded and set in the request HTTP body. + @param success A block object to be executed when the request operation finishes successfully. This block has no return value and takes two arguments: the created request operation and the object created from the response data of request. + @param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes two arguments: the created request operation and the `NSError` object describing the network or parsing error that occurred. + + @see -HTTPRequestOperationWithRequest:success:failure: + */ +- (void)putPath:(NSString *)path + parameters:(NSDictionary *)parameters + success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success + failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure; + +/** + Creates an `AFHTTPRequestOperation` with a `DELETE` request, and enqueues it to the HTTP client's operation queue. + + @param path The path to be appended to the HTTP client's base URL and used as the request URL. + @param parameters The parameters to be encoded and appended as the query string for the request URL. + @param success A block object to be executed when the request operation finishes successfully. This block has no return value and takes two arguments: the created request operation and the object created from the response data of request. + @param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes two arguments: the created request operation and the `NSError` object describing the network or parsing error that occurred. + + @see -HTTPRequestOperationWithRequest:success:failure: + */ +- (void)deletePath:(NSString *)path + parameters:(NSDictionary *)parameters + success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success + failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure; + +/** + Creates an `AFHTTPRequestOperation` with a `PATCH` request, and enqueues it to the HTTP client's operation queue. + + @param path The path to be appended to the HTTP client's base URL and used as the request URL. + @param parameters The parameters to be encoded and set in the request HTTP body. + @param success A block object to be executed when the request operation finishes successfully. This block has no return value and takes two arguments: the created request operation and the object created from the response data of request. + @param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes two arguments: the created request operation and the `NSError` object describing the network or parsing error that occurred. + + @see -HTTPRequestOperationWithRequest:success:failure: + */ +- (void)patchPath:(NSString *)path + parameters:(NSDictionary *)parameters + success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success + failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure; +@end + +///---------------- +/// @name Constants +///---------------- + +/** + ## Network Reachability + + The following constants are provided by `AFHTTPClient` as possible network reachability statuses. + + enum { + AFNetworkReachabilityStatusUnknown, + AFNetworkReachabilityStatusNotReachable, + AFNetworkReachabilityStatusReachableViaWWAN, + AFNetworkReachabilityStatusReachableViaWiFi, + } + + `AFNetworkReachabilityStatusUnknown` + The `baseURL` host reachability is not known. + + `AFNetworkReachabilityStatusNotReachable` + The `baseURL` host cannot be reached. + + `AFNetworkReachabilityStatusReachableViaWWAN` + The `baseURL` host can be reached via a cellular connection, such as EDGE or GPRS. + + `AFNetworkReachabilityStatusReachableViaWiFi` + The `baseURL` host can be reached via a Wi-Fi connection. + + ### Keys for Notification UserInfo Dictionary + + Strings that are used as keys in a `userInfo` dictionary in a network reachability status change notification. + + `AFNetworkingReachabilityNotificationStatusItem` + A key in the userInfo dictionary in a `AFNetworkingReachabilityDidChangeNotification` notification. + The corresponding value is an `NSNumber` object representing the `AFNetworkReachabilityStatus` value for the current reachability status. + + ## Parameter Encoding + + The following constants are provided by `AFHTTPClient` as possible methods for serializing parameters into query string or message body values. + + enum { + AFFormURLParameterEncoding, + AFJSONParameterEncoding, + AFPropertyListParameterEncoding, + } + + `AFFormURLParameterEncoding` + Parameters are encoded into field/key pairs in the URL query string for `GET` `HEAD` and `DELETE` requests, and in the message body otherwise. Dictionary keys are sorted with the `caseInsensitiveCompare:` selector of their description, in order to mitigate the possibility of ambiguous query strings being generated non-deterministically. See the warning for the `parameterEncoding` property for additional information. + + `AFJSONParameterEncoding` + Parameters are encoded into JSON in the message body. + + `AFPropertyListParameterEncoding` + Parameters are encoded into a property list in the message body. + */ + +///---------------- +/// @name Functions +///---------------- + +/** + Returns a query string constructed by a set of parameters, using the specified encoding. + + Query strings are constructed by collecting each key-value pair, percent escaping a string representation of the key-value pair, and then joining the pairs with "&". + + If a query string pair has a an `NSArray` for its value, each member of the array will be represented in the format `field[]=value1&field[]value2`. Otherwise, the pair will be formatted as "field=value". String representations of both keys and values are derived using the `-description` method. The constructed query string does not include the ? character used to delimit the query component. + + @param parameters The parameters used to construct the query string + @param encoding The encoding to use in constructing the query string. If you are uncertain of the correct encoding, you should use UTF-8 (`NSUTF8StringEncoding`), which is the encoding designated by RFC 3986 as the correct encoding for use in URLs. + + @return A percent-escaped query string + */ +extern NSString * AFQueryStringFromParametersWithEncoding(NSDictionary *parameters, NSStringEncoding encoding); + +///-------------------- +/// @name Notifications +///-------------------- + +/** + Posted when network reachability changes. + This notification assigns no notification object. The `userInfo` dictionary contains an `NSNumber` object under the `AFNetworkingReachabilityNotificationStatusItem` key, representing the `AFNetworkReachabilityStatus` value for the current network reachability. + + @warning In order for network reachability to be monitored, include the `SystemConfiguration` framework in the active target's "Link Binary With Library" build phase, and add `#import ` to the header prefix of the project (`Prefix.pch`). + */ +#ifdef _SYSTEMCONFIGURATION_H +extern NSString * const AFNetworkingReachabilityDidChangeNotification; +extern NSString * const AFNetworkingReachabilityNotificationStatusItem; +#endif + +#pragma mark - + +extern NSUInteger const kAFUploadStream3GSuggestedPacketSize; +extern NSTimeInterval const kAFUploadStream3GSuggestedDelay; + +/** + The `AFMultipartFormData` protocol defines the methods supported by the parameter in the block argument of `AFHTTPClient -multipartFormRequestWithMethod:path:parameters:constructingBodyWithBlock:`. + */ +@protocol AFMultipartFormData + +/** + Appends the HTTP header `Content-Disposition: file; filename=#{generated filename}; name=#{name}"` and `Content-Type: #{generated mimeType}`, followed by the encoded file data and the multipart form boundary. + + The filename and MIME type for this data in the form will be automatically generated, using the last path component of the `fileURL` and system associated MIME type for the `fileURL` extension, respectively. + + @param fileURL The URL corresponding to the file whose content will be appended to the form. This parameter must not be `nil`. + @param name The name to be associated with the specified data. This parameter must not be `nil`. + @param error If an error occurs, upon return contains an `NSError` object that describes the problem. + + @return `YES` if the file data was successfully appended, otherwise `NO`. + */ +- (BOOL)appendPartWithFileURL:(NSURL *)fileURL + name:(NSString *)name + error:(NSError * __autoreleasing *)error; + +/** + Appends the HTTP header `Content-Disposition: file; filename=#{filename}; name=#{name}"` and `Content-Type: #{mimeType}`, followed by the encoded file data and the multipart form boundary. + + @param fileURL The URL corresponding to the file whose content will be appended to the form. This parameter must not be `nil`. + @param name The name to be associated with the specified data. This parameter must not be `nil`. + @param fileName The file name to be used in the `Content-Disposition` header. This parameter must not be `nil`. + @param mimeType The declared MIME type of the file data. This parameter must not be `nil`. + @param error If an error occurs, upon return contains an `NSError` object that describes the problem. + + @return `YES` if the file data was successfully appended otherwise `NO`. + */ +- (BOOL)appendPartWithFileURL:(NSURL *)fileURL + name:(NSString *)name + fileName:(NSString *)fileName + mimeType:(NSString *)mimeType + error:(NSError * __autoreleasing *)error; + +/** + Appends the HTTP header `Content-Disposition: file; filename=#{filename}; name=#{name}"` and `Content-Type: #{mimeType}`, followed by the data from the input stream and the multipart form boundary. + + @param inputStream The input stream to be appended to the form data + @param name The name to be associated with the specified input stream. This parameter must not be `nil`. + @param fileName The filename to be associated with the specified input stream. This parameter must not be `nil`. + @param length The length of the specified input stream in bytes. + @param mimeType The MIME type of the specified data. (For example, the MIME type for a JPEG image is image/jpeg.) For a list of valid MIME types, see http://www.iana.org/assignments/media-types/. This parameter must not be `nil`. + */ +- (void)appendPartWithInputStream:(NSInputStream *)inputStream + name:(NSString *)name + fileName:(NSString *)fileName + length:(unsigned long long)length + mimeType:(NSString *)mimeType; + +/** + Appends the HTTP header `Content-Disposition: file; filename=#{filename}; name=#{name}"` and `Content-Type: #{mimeType}`, followed by the encoded file data and the multipart form boundary. + + @param data The data to be encoded and appended to the form data. + @param name The name to be associated with the specified data. This parameter must not be `nil`. + @param fileName The filename to be associated with the specified data. This parameter must not be `nil`. + @param mimeType The MIME type of the specified data. (For example, the MIME type for a JPEG image is image/jpeg.) For a list of valid MIME types, see http://www.iana.org/assignments/media-types/. This parameter must not be `nil`. + */ +- (void)appendPartWithFileData:(NSData *)data + name:(NSString *)name + fileName:(NSString *)fileName + mimeType:(NSString *)mimeType; + +/** + Appends the HTTP headers `Content-Disposition: form-data; name=#{name}"`, followed by the encoded data and the multipart form boundary. + + @param data The data to be encoded and appended to the form data. + @param name The name to be associated with the specified data. This parameter must not be `nil`. + */ + +- (void)appendPartWithFormData:(NSData *)data + name:(NSString *)name; + + +/** + Appends HTTP headers, followed by the encoded data and the multipart form boundary. + + @param headers The HTTP headers to be appended to the form data. + @param body The data to be encoded and appended to the form data. + */ +- (void)appendPartWithHeaders:(NSDictionary *)headers + body:(NSData *)body; + +/** + Throttles request bandwidth by limiting the packet size and adding a delay for each chunk read from the upload stream. + + When uploading over a 3G or EDGE connection, requests may fail with "request body stream exhausted". Setting a maximum packet size and delay according to the recommended values (`kAFUploadStream3GSuggestedPacketSize` and `kAFUploadStream3GSuggestedDelay`) lowers the risk of the input stream exceeding its allocated bandwidth. Unfortunately, as of iOS 6, there is no definite way to distinguish between a 3G, EDGE, or LTE connection. As such, it is not recommended that you throttle bandwidth based solely on network reachability. Instead, you should consider checking for the "request body stream exhausted" in a failure block, and then retrying the request with throttled bandwidth. + + @param numberOfBytes Maximum packet size, in number of bytes. The default packet size for an input stream is 32kb. + @param delay Duration of delay each time a packet is read. By default, no delay is set. + */ +- (void)throttleBandwidthWithPacketSize:(NSUInteger)numberOfBytes + delay:(NSTimeInterval)delay; + +@end diff --git a/Pods/AFNetworking/AFNetworking/AFHTTPClient.m b/Pods/AFNetworking/AFNetworking/AFHTTPClient.m new file mode 100644 index 0000000..2902e77 --- /dev/null +++ b/Pods/AFNetworking/AFNetworking/AFHTTPClient.m @@ -0,0 +1,1403 @@ +// AFHTTPClient.m +// +// Copyright (c) 2011 Gowalla (http://gowalla.com/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import + +#import "AFHTTPClient.h" +#import "AFHTTPRequestOperation.h" + +#import + +#ifdef _SYSTEMCONFIGURATION_H +#import +#import +#import +#import +#import +#endif + +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) +#import +#endif + +#ifdef _SYSTEMCONFIGURATION_H +NSString * const AFNetworkingReachabilityDidChangeNotification = @"com.alamofire.networking.reachability.change"; +NSString * const AFNetworkingReachabilityNotificationStatusItem = @"AFNetworkingReachabilityNotificationStatusItem"; + +typedef SCNetworkReachabilityRef AFNetworkReachabilityRef; +typedef void (^AFNetworkReachabilityStatusBlock)(AFNetworkReachabilityStatus status); +#else +typedef id AFNetworkReachabilityRef; +#endif + +typedef void (^AFCompletionBlock)(void); + +static NSString * AFBase64EncodedStringFromString(NSString *string) { + NSData *data = [NSData dataWithBytes:[string UTF8String] length:[string lengthOfBytesUsingEncoding:NSUTF8StringEncoding]]; + NSUInteger length = [data length]; + NSMutableData *mutableData = [NSMutableData dataWithLength:((length + 2) / 3) * 4]; + + uint8_t *input = (uint8_t *)[data bytes]; + uint8_t *output = (uint8_t *)[mutableData mutableBytes]; + + for (NSUInteger i = 0; i < length; i += 3) { + NSUInteger value = 0; + for (NSUInteger j = i; j < (i + 3); j++) { + value <<= 8; + if (j < length) { + value |= (0xFF & input[j]); + } + } + + static uint8_t const kAFBase64EncodingTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + NSUInteger idx = (i / 3) * 4; + output[idx + 0] = kAFBase64EncodingTable[(value >> 18) & 0x3F]; + output[idx + 1] = kAFBase64EncodingTable[(value >> 12) & 0x3F]; + output[idx + 2] = (i + 1) < length ? kAFBase64EncodingTable[(value >> 6) & 0x3F] : '='; + output[idx + 3] = (i + 2) < length ? kAFBase64EncodingTable[(value >> 0) & 0x3F] : '='; + } + + return [[NSString alloc] initWithData:mutableData encoding:NSASCIIStringEncoding]; +} + +static NSString * const kAFCharactersToBeEscapedInQueryString = @":/?&=;+!@#$()',*"; + +static NSString * AFPercentEscapedQueryStringKeyFromStringWithEncoding(NSString *string, NSStringEncoding encoding) { + static NSString * const kAFCharactersToLeaveUnescapedInQueryStringPairKey = @"[]."; + + return (__bridge_transfer NSString *)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (__bridge CFStringRef)string, (__bridge CFStringRef)kAFCharactersToLeaveUnescapedInQueryStringPairKey, (__bridge CFStringRef)kAFCharactersToBeEscapedInQueryString, CFStringConvertNSStringEncodingToEncoding(encoding)); +} + +static NSString * AFPercentEscapedQueryStringValueFromStringWithEncoding(NSString *string, NSStringEncoding encoding) { + return (__bridge_transfer NSString *)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (__bridge CFStringRef)string, NULL, (__bridge CFStringRef)kAFCharactersToBeEscapedInQueryString, CFStringConvertNSStringEncodingToEncoding(encoding)); +} + +#pragma mark - + +@interface AFQueryStringPair : NSObject +@property (readwrite, nonatomic, strong) id field; +@property (readwrite, nonatomic, strong) id value; + +- (id)initWithField:(id)field value:(id)value; + +- (NSString *)URLEncodedStringValueWithEncoding:(NSStringEncoding)stringEncoding; +@end + +@implementation AFQueryStringPair +@synthesize field = _field; +@synthesize value = _value; + +- (id)initWithField:(id)field value:(id)value { + self = [super init]; + if (!self) { + return nil; + } + + self.field = field; + self.value = value; + + return self; +} + +- (NSString *)URLEncodedStringValueWithEncoding:(NSStringEncoding)stringEncoding { + if (!self.value || [self.value isEqual:[NSNull null]]) { + return AFPercentEscapedQueryStringKeyFromStringWithEncoding([self.field description], stringEncoding); + } else { + return [NSString stringWithFormat:@"%@=%@", AFPercentEscapedQueryStringKeyFromStringWithEncoding([self.field description], stringEncoding), AFPercentEscapedQueryStringValueFromStringWithEncoding([self.value description], stringEncoding)]; + } +} + +@end + +#pragma mark - + +extern NSArray * AFQueryStringPairsFromDictionary(NSDictionary *dictionary); +extern NSArray * AFQueryStringPairsFromKeyAndValue(NSString *key, id value); + +NSString * AFQueryStringFromParametersWithEncoding(NSDictionary *parameters, NSStringEncoding stringEncoding) { + NSMutableArray *mutablePairs = [NSMutableArray array]; + for (AFQueryStringPair *pair in AFQueryStringPairsFromDictionary(parameters)) { + [mutablePairs addObject:[pair URLEncodedStringValueWithEncoding:stringEncoding]]; + } + + return [mutablePairs componentsJoinedByString:@"&"]; +} + +NSArray * AFQueryStringPairsFromDictionary(NSDictionary *dictionary) { + return AFQueryStringPairsFromKeyAndValue(nil, dictionary); +} + +NSArray * AFQueryStringPairsFromKeyAndValue(NSString *key, id value) { + NSMutableArray *mutableQueryStringComponents = [NSMutableArray array]; + + if ([value isKindOfClass:[NSDictionary class]]) { + NSDictionary *dictionary = value; + // Sort dictionary keys to ensure consistent ordering in query string, which is important when deserializing potentially ambiguous sequences, such as an array of dictionaries + NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"description" ascending:YES selector:@selector(caseInsensitiveCompare:)]; + for (id nestedKey in [dictionary.allKeys sortedArrayUsingDescriptors:@[ sortDescriptor ]]) { + id nestedValue = [dictionary objectForKey:nestedKey]; + if (nestedValue) { + [mutableQueryStringComponents addObjectsFromArray:AFQueryStringPairsFromKeyAndValue((key ? [NSString stringWithFormat:@"%@[%@]", key, nestedKey] : nestedKey), nestedValue)]; + } + } + } else if ([value isKindOfClass:[NSArray class]]) { + NSArray *array = value; + for (id nestedValue in array) { + [mutableQueryStringComponents addObjectsFromArray:AFQueryStringPairsFromKeyAndValue([NSString stringWithFormat:@"%@[]", key], nestedValue)]; + } + } else if ([value isKindOfClass:[NSSet class]]) { + NSSet *set = value; + for (id obj in set) { + [mutableQueryStringComponents addObjectsFromArray:AFQueryStringPairsFromKeyAndValue(key, obj)]; + } + } else { + [mutableQueryStringComponents addObject:[[AFQueryStringPair alloc] initWithField:key value:value]]; + } + + return mutableQueryStringComponents; +} + +@interface AFStreamingMultipartFormData : NSObject +- (id)initWithURLRequest:(NSMutableURLRequest *)urlRequest + stringEncoding:(NSStringEncoding)encoding; + +- (NSMutableURLRequest *)requestByFinalizingMultipartFormData; +@end + +#pragma mark - + +@interface AFHTTPClient () +@property (readwrite, nonatomic, strong) NSURL *baseURL; +@property (readwrite, nonatomic, strong) NSMutableArray *registeredHTTPOperationClassNames; +@property (readwrite, nonatomic, strong) NSMutableDictionary *defaultHeaders; +@property (readwrite, nonatomic, strong) NSURLCredential *defaultCredential; +@property (readwrite, nonatomic, strong) NSOperationQueue *operationQueue; +#ifdef _SYSTEMCONFIGURATION_H +@property (readwrite, nonatomic, assign) AFNetworkReachabilityRef networkReachability; +@property (readwrite, nonatomic, assign) AFNetworkReachabilityStatus networkReachabilityStatus; +@property (readwrite, nonatomic, copy) AFNetworkReachabilityStatusBlock networkReachabilityStatusBlock; +#endif + +#ifdef _SYSTEMCONFIGURATION_H +- (void)startMonitoringNetworkReachability; +- (void)stopMonitoringNetworkReachability; +#endif +@end + +@implementation AFHTTPClient +@synthesize baseURL = _baseURL; +@synthesize stringEncoding = _stringEncoding; +@synthesize parameterEncoding = _parameterEncoding; +@synthesize registeredHTTPOperationClassNames = _registeredHTTPOperationClassNames; +@synthesize defaultHeaders = _defaultHeaders; +@synthesize defaultCredential = _defaultCredential; +@synthesize operationQueue = _operationQueue; +#ifdef _SYSTEMCONFIGURATION_H +@synthesize networkReachability = _networkReachability; +@synthesize networkReachabilityStatus = _networkReachabilityStatus; +@synthesize networkReachabilityStatusBlock = _networkReachabilityStatusBlock; +#endif +@synthesize defaultSSLPinningMode = _defaultSSLPinningMode; +@synthesize allowsInvalidSSLCertificate = _allowsInvalidSSLCertificate; + ++ (instancetype)clientWithBaseURL:(NSURL *)url { + return [[self alloc] initWithBaseURL:url]; +} + +- (id)init { + @throw [NSException exceptionWithName:NSInternalInconsistencyException reason:[NSString stringWithFormat:@"%@ Failed to call designated initializer. Invoke `initWithBaseURL:` instead.", NSStringFromClass([self class])] userInfo:nil]; +} + +- (id)initWithBaseURL:(NSURL *)url { + NSParameterAssert(url); + + self = [super init]; + if (!self) { + return nil; + } + + // Ensure terminal slash for baseURL path, so that NSURL +URLWithString:relativeToURL: works as expected + if ([[url path] length] > 0 && ![[url absoluteString] hasSuffix:@"/"]) { + url = [url URLByAppendingPathComponent:@""]; + } + + self.baseURL = url; + + self.stringEncoding = NSUTF8StringEncoding; + self.parameterEncoding = AFFormURLParameterEncoding; + + self.registeredHTTPOperationClassNames = [NSMutableArray array]; + + self.defaultHeaders = [NSMutableDictionary dictionary]; + + // Accept-Language HTTP Header; see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4 + NSMutableArray *acceptLanguagesComponents = [NSMutableArray array]; + [[NSLocale preferredLanguages] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + float q = 1.0f - (idx * 0.1f); + [acceptLanguagesComponents addObject:[NSString stringWithFormat:@"%@;q=%0.1g", obj, q]]; + *stop = q <= 0.5f; + }]; + [self setDefaultHeader:@"Accept-Language" value:[acceptLanguagesComponents componentsJoinedByString:@", "]]; + + NSString *userAgent = nil; +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wgnu" +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) + // User-Agent Header; see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.43 + userAgent = [NSString stringWithFormat:@"%@/%@ (%@; iOS %@; Scale/%0.2f)", [[[NSBundle mainBundle] infoDictionary] objectForKey:(__bridge NSString *)kCFBundleExecutableKey] ?: [[[NSBundle mainBundle] infoDictionary] objectForKey:(__bridge NSString *)kCFBundleIdentifierKey], (__bridge id)CFBundleGetValueForInfoDictionaryKey(CFBundleGetMainBundle(), kCFBundleVersionKey) ?: [[[NSBundle mainBundle] infoDictionary] objectForKey:(__bridge NSString *)kCFBundleVersionKey], [[UIDevice currentDevice] model], [[UIDevice currentDevice] systemVersion], ([[UIScreen mainScreen] respondsToSelector:@selector(scale)] ? [[UIScreen mainScreen] scale] : 1.0f)]; +#elif defined(__MAC_OS_X_VERSION_MIN_REQUIRED) + userAgent = [NSString stringWithFormat:@"%@/%@ (Mac OS X %@)", [[[NSBundle mainBundle] infoDictionary] objectForKey:(__bridge NSString *)kCFBundleExecutableKey] ?: [[[NSBundle mainBundle] infoDictionary] objectForKey:(__bridge NSString *)kCFBundleIdentifierKey], [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"] ?: [[[NSBundle mainBundle] infoDictionary] objectForKey:(__bridge NSString *)kCFBundleVersionKey], [[NSProcessInfo processInfo] operatingSystemVersionString]]; +#endif +#pragma clang diagnostic pop + if (userAgent) { + if (![userAgent canBeConvertedToEncoding:NSASCIIStringEncoding]) { + NSMutableString *mutableUserAgent = [userAgent mutableCopy]; + if (CFStringTransform((__bridge CFMutableStringRef)(mutableUserAgent), NULL, kCFStringTransformToLatin, false)) { + userAgent = mutableUserAgent; + } + } + [self setDefaultHeader:@"User-Agent" value:userAgent]; + } + +#ifdef _SYSTEMCONFIGURATION_H + self.networkReachabilityStatus = AFNetworkReachabilityStatusUnknown; + [self startMonitoringNetworkReachability]; +#endif + + self.operationQueue = [[NSOperationQueue alloc] init]; + [self.operationQueue setMaxConcurrentOperationCount:NSOperationQueueDefaultMaxConcurrentOperationCount]; + + // #ifdef included for backwards-compatibility +#ifdef _AFNETWORKING_ALLOW_INVALID_SSL_CERTIFICATES_ + self.allowsInvalidSSLCertificate = YES; +#endif + + return self; +} + +- (void)dealloc { +#ifdef _SYSTEMCONFIGURATION_H + [self stopMonitoringNetworkReachability]; +#endif +} + +- (NSString *)description { + return [NSString stringWithFormat:@"<%@: %p, baseURL: %@, defaultHeaders: %@, registeredOperationClasses: %@, operationQueue: %@>", NSStringFromClass([self class]), self, [self.baseURL absoluteString], self.defaultHeaders, self.registeredHTTPOperationClassNames, self.operationQueue]; +} + +#pragma mark - + +#ifdef _SYSTEMCONFIGURATION_H +static BOOL AFURLHostIsIPAddress(NSURL *url) { + struct sockaddr_in sa_in; + struct sockaddr_in6 sa_in6; + + return [url host] && (inet_pton(AF_INET, [[url host] UTF8String], &sa_in) == 1 || inet_pton(AF_INET6, [[url host] UTF8String], &sa_in6) == 1); +} + +static AFNetworkReachabilityStatus AFNetworkReachabilityStatusForFlags(SCNetworkReachabilityFlags flags) { + BOOL isReachable = ((flags & kSCNetworkReachabilityFlagsReachable) != 0); + BOOL needsConnection = ((flags & kSCNetworkReachabilityFlagsConnectionRequired) != 0); + BOOL canConnectionAutomatically = (((flags & kSCNetworkReachabilityFlagsConnectionOnDemand ) != 0) || ((flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) != 0)); + BOOL canConnectWithoutUserInteraction = (canConnectionAutomatically && (flags & kSCNetworkReachabilityFlagsInterventionRequired) == 0); + BOOL isNetworkReachable = (isReachable && (!needsConnection || canConnectWithoutUserInteraction)); + + AFNetworkReachabilityStatus status = AFNetworkReachabilityStatusUnknown; + if (isNetworkReachable == NO) { + status = AFNetworkReachabilityStatusNotReachable; + } +#if TARGET_OS_IPHONE + else if ((flags & kSCNetworkReachabilityFlagsIsWWAN) != 0) { + status = AFNetworkReachabilityStatusReachableViaWWAN; + } +#endif + else { + status = AFNetworkReachabilityStatusReachableViaWiFi; + } + + return status; +} + +static void AFNetworkReachabilityCallback(SCNetworkReachabilityRef __unused target, SCNetworkReachabilityFlags flags, void *info) { + AFNetworkReachabilityStatus status = AFNetworkReachabilityStatusForFlags(flags); + AFNetworkReachabilityStatusBlock block = (__bridge AFNetworkReachabilityStatusBlock)info; + if (block) { + block(status); + } + + dispatch_async(dispatch_get_main_queue(), ^{ + NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; + [notificationCenter postNotificationName:AFNetworkingReachabilityDidChangeNotification object:nil userInfo:[NSDictionary dictionaryWithObject:[NSNumber numberWithInteger:status] forKey:AFNetworkingReachabilityNotificationStatusItem]]; + }); +} + +static const void * AFNetworkReachabilityRetainCallback(const void *info) { + return Block_copy(info); +} + +static void AFNetworkReachabilityReleaseCallback(const void *info) { + if (info) { + Block_release(info); + } +} + +- (void)startMonitoringNetworkReachability { + [self stopMonitoringNetworkReachability]; + + if (!self.baseURL) { + return; + } + + self.networkReachability = SCNetworkReachabilityCreateWithName(kCFAllocatorDefault, [[self.baseURL host] UTF8String]); + + if (!self.networkReachability) { + return; + } + + __weak __typeof(&*self)weakSelf = self; + AFNetworkReachabilityStatusBlock callback = ^(AFNetworkReachabilityStatus status) { + __strong __typeof(&*weakSelf)strongSelf = weakSelf; + if (!strongSelf) { + return; + } + + strongSelf.networkReachabilityStatus = status; + if (strongSelf.networkReachabilityStatusBlock) { + strongSelf.networkReachabilityStatusBlock(status); + } + }; + + SCNetworkReachabilityContext context = {0, (__bridge void *)callback, AFNetworkReachabilityRetainCallback, AFNetworkReachabilityReleaseCallback, NULL}; + SCNetworkReachabilitySetCallback(self.networkReachability, AFNetworkReachabilityCallback, &context); + + /* Network reachability monitoring does not establish a baseline for IP addresses as it does for hostnames, so if the base URL host is an IP address, the initial reachability callback is manually triggered. + */ + if (AFURLHostIsIPAddress(self.baseURL)) { + SCNetworkReachabilityFlags flags; + SCNetworkReachabilityGetFlags(self.networkReachability, &flags); + dispatch_async(dispatch_get_main_queue(), ^{ + AFNetworkReachabilityStatus status = AFNetworkReachabilityStatusForFlags(flags); + callback(status); + }); + } + + SCNetworkReachabilityScheduleWithRunLoop(self.networkReachability, CFRunLoopGetMain(), kCFRunLoopCommonModes); +} + +- (void)stopMonitoringNetworkReachability { + if (self.networkReachability) { + SCNetworkReachabilityUnscheduleFromRunLoop(self.networkReachability, CFRunLoopGetMain(), kCFRunLoopCommonModes); + + CFRelease(_networkReachability); + _networkReachability = NULL; + } +} + +- (void)setReachabilityStatusChangeBlock:(void (^)(AFNetworkReachabilityStatus status))block { + self.networkReachabilityStatusBlock = block; +} +#endif + +#pragma mark - + +- (BOOL)registerHTTPOperationClass:(Class)operationClass { + if (![operationClass isSubclassOfClass:[AFHTTPRequestOperation class]]) { + return NO; + } + + NSString *className = NSStringFromClass(operationClass); + [self.registeredHTTPOperationClassNames removeObject:className]; + [self.registeredHTTPOperationClassNames insertObject:className atIndex:0]; + + return YES; +} + +- (void)unregisterHTTPOperationClass:(Class)operationClass { + NSString *className = NSStringFromClass(operationClass); + [self.registeredHTTPOperationClassNames removeObject:className]; +} + +#pragma mark - + +- (NSString *)defaultValueForHeader:(NSString *)header { + return [self.defaultHeaders valueForKey:header]; +} + +- (void)setDefaultHeader:(NSString *)header value:(NSString *)value { + [self.defaultHeaders setValue:value forKey:header]; +} + +- (void)setAuthorizationHeaderWithUsername:(NSString *)username password:(NSString *)password { + NSString *basicAuthCredentials = [NSString stringWithFormat:@"%@:%@", username, password]; + [self setDefaultHeader:@"Authorization" value:[NSString stringWithFormat:@"Basic %@", AFBase64EncodedStringFromString(basicAuthCredentials)]]; +} + +- (void)setAuthorizationHeaderWithToken:(NSString *)token { + [self setDefaultHeader:@"Authorization" value:[NSString stringWithFormat:@"Token token=\"%@\"", token]]; +} + +- (void)clearAuthorizationHeader { + [self.defaultHeaders removeObjectForKey:@"Authorization"]; +} + +#pragma mark - + +- (NSMutableURLRequest *)requestWithMethod:(NSString *)method + path:(NSString *)path + parameters:(NSDictionary *)parameters +{ + NSParameterAssert(method); + + if (!path) { + path = @""; + } + + NSURL *url = [NSURL URLWithString:path relativeToURL:self.baseURL]; + NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url]; + [request setHTTPMethod:method]; + [request setAllHTTPHeaderFields:self.defaultHeaders]; + + if (parameters) { + if ([method isEqualToString:@"GET"] || [method isEqualToString:@"HEAD"] || [method isEqualToString:@"DELETE"]) { + url = [NSURL URLWithString:[[url absoluteString] stringByAppendingFormat:[path rangeOfString:@"?"].location == NSNotFound ? @"?%@" : @"&%@", AFQueryStringFromParametersWithEncoding(parameters, self.stringEncoding)]]; + [request setURL:url]; + } else { + NSString *charset = (__bridge NSString *)CFStringConvertEncodingToIANACharSetName(CFStringConvertNSStringEncodingToEncoding(self.stringEncoding)); + NSError *error = nil; + + switch (self.parameterEncoding) { + case AFFormURLParameterEncoding:; + [request setValue:[NSString stringWithFormat:@"application/x-www-form-urlencoded; charset=%@", charset] forHTTPHeaderField:@"Content-Type"]; + [request setHTTPBody:[AFQueryStringFromParametersWithEncoding(parameters, self.stringEncoding) dataUsingEncoding:self.stringEncoding]]; + break; + case AFJSONParameterEncoding:; + [request setValue:[NSString stringWithFormat:@"application/json; charset=%@", charset] forHTTPHeaderField:@"Content-Type"]; + [request setHTTPBody:[NSJSONSerialization dataWithJSONObject:parameters options:(NSJSONWritingOptions)0 error:&error]]; + break; + case AFPropertyListParameterEncoding:; + [request setValue:[NSString stringWithFormat:@"application/x-plist; charset=%@", charset] forHTTPHeaderField:@"Content-Type"]; + [request setHTTPBody:[NSPropertyListSerialization dataWithPropertyList:parameters format:NSPropertyListXMLFormat_v1_0 options:0 error:&error]]; + break; + } + + if (error) { + NSLog(@"%@ %@: %@", [self class], NSStringFromSelector(_cmd), error); + } + } + } + + return request; +} + +- (NSMutableURLRequest *)multipartFormRequestWithMethod:(NSString *)method + path:(NSString *)path + parameters:(NSDictionary *)parameters + constructingBodyWithBlock:(void (^)(id formData))block +{ + NSParameterAssert(method); + NSParameterAssert(![method isEqualToString:@"GET"] && ![method isEqualToString:@"HEAD"]); + + NSMutableURLRequest *request = [self requestWithMethod:method path:path parameters:nil]; + + __block AFStreamingMultipartFormData *formData = [[AFStreamingMultipartFormData alloc] initWithURLRequest:request stringEncoding:self.stringEncoding]; + + if (parameters) { + for (AFQueryStringPair *pair in AFQueryStringPairsFromDictionary(parameters)) { + NSData *data = nil; + if ([pair.value isKindOfClass:[NSData class]]) { + data = pair.value; + } else if ([pair.value isEqual:[NSNull null]]) { + data = [NSData data]; + } else { + data = [[pair.value description] dataUsingEncoding:self.stringEncoding]; + } + + if (data) { + [formData appendPartWithFormData:data name:[pair.field description]]; + } + } + } + + if (block) { + block(formData); + } + + return [formData requestByFinalizingMultipartFormData]; +} + +- (AFHTTPRequestOperation *)HTTPRequestOperationWithRequest:(NSURLRequest *)urlRequest + success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success + failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure +{ + AFHTTPRequestOperation *operation = nil; + + for (NSString *className in self.registeredHTTPOperationClassNames) { + Class operationClass = NSClassFromString(className); + if (operationClass && [operationClass canProcessRequest:urlRequest]) { + operation = [(AFHTTPRequestOperation *)[operationClass alloc] initWithRequest:urlRequest]; + break; + } + } + + if (!operation) { + operation = [[AFHTTPRequestOperation alloc] initWithRequest:urlRequest]; + } + + [operation setCompletionBlockWithSuccess:success failure:failure]; + + operation.credential = self.defaultCredential; + operation.SSLPinningMode = self.defaultSSLPinningMode; + operation.allowsInvalidSSLCertificate = self.allowsInvalidSSLCertificate; + + return operation; +} + +#pragma mark - + +- (void)enqueueHTTPRequestOperation:(AFHTTPRequestOperation *)operation { + [self.operationQueue addOperation:operation]; +} + +- (void)cancelAllHTTPOperationsWithMethod:(NSString *)method + path:(NSString *)path +{ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wgnu" + NSString *pathToBeMatched = [[[self requestWithMethod:(method ?: @"GET") path:path parameters:nil] URL] path]; +#pragma clang diagnostic pop + + for (NSOperation *operation in [self.operationQueue operations]) { + if (![operation isKindOfClass:[AFHTTPRequestOperation class]]) { + continue; + } + + BOOL hasMatchingMethod = !method || [method isEqualToString:[[(AFHTTPRequestOperation *)operation request] HTTPMethod]]; + BOOL hasMatchingPath = [[[[(AFHTTPRequestOperation *)operation request] URL] path] isEqual:pathToBeMatched]; + + if (hasMatchingMethod && hasMatchingPath) { + [operation cancel]; + } + } +} + +- (void)enqueueBatchOfHTTPRequestOperationsWithRequests:(NSArray *)urlRequests + progressBlock:(void (^)(NSUInteger numberOfFinishedOperations, NSUInteger totalNumberOfOperations))progressBlock + completionBlock:(void (^)(NSArray *operations))completionBlock +{ + NSMutableArray *mutableOperations = [NSMutableArray array]; + for (NSURLRequest *request in urlRequests) { + AFHTTPRequestOperation *operation = [self HTTPRequestOperationWithRequest:request success:nil failure:nil]; + [mutableOperations addObject:operation]; + } + + [self enqueueBatchOfHTTPRequestOperations:mutableOperations progressBlock:progressBlock completionBlock:completionBlock]; +} + +- (void)enqueueBatchOfHTTPRequestOperations:(NSArray *)operations + progressBlock:(void (^)(NSUInteger numberOfFinishedOperations, NSUInteger totalNumberOfOperations))progressBlock + completionBlock:(void (^)(NSArray *operations))completionBlock +{ + __block dispatch_group_t dispatchGroup = dispatch_group_create(); + NSBlockOperation *batchedOperation = [NSBlockOperation blockOperationWithBlock:^{ + dispatch_group_notify(dispatchGroup, dispatch_get_main_queue(), ^{ + if (completionBlock) { + completionBlock(operations); + } + }); +#if !OS_OBJECT_USE_OBJC + dispatch_release(dispatchGroup); +#endif + }]; + + for (AFHTTPRequestOperation *operation in operations) { + AFCompletionBlock originalCompletionBlock = [operation.completionBlock copy]; + __weak __typeof(&*operation)weakOperation = operation; + operation.completionBlock = ^{ + __strong __typeof(&*weakOperation)strongOperation = weakOperation; +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wgnu" + dispatch_queue_t queue = strongOperation.successCallbackQueue ?: dispatch_get_main_queue(); +#pragma clang diagnostic pop + dispatch_group_async(dispatchGroup, queue, ^{ + if (originalCompletionBlock) { + originalCompletionBlock(); + } + + NSUInteger numberOfFinishedOperations = [[operations indexesOfObjectsPassingTest:^BOOL(id op, NSUInteger __unused idx, BOOL __unused *stop) { + return [op isFinished]; + }] count]; + + if (progressBlock) { + progressBlock(numberOfFinishedOperations, [operations count]); + } + + dispatch_group_leave(dispatchGroup); + }); + }; + + dispatch_group_enter(dispatchGroup); + [batchedOperation addDependency:operation]; + } + [self.operationQueue addOperations:operations waitUntilFinished:NO]; + [self.operationQueue addOperation:batchedOperation]; +} + +#pragma mark - + +- (void)getPath:(NSString *)path + parameters:(NSDictionary *)parameters + success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success + failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure +{ + NSURLRequest *request = [self requestWithMethod:@"GET" path:path parameters:parameters]; + AFHTTPRequestOperation *operation = [self HTTPRequestOperationWithRequest:request success:success failure:failure]; + [self enqueueHTTPRequestOperation:operation]; +} + +- (void)postPath:(NSString *)path + parameters:(NSDictionary *)parameters + success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success + failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure +{ + NSURLRequest *request = [self requestWithMethod:@"POST" path:path parameters:parameters]; + AFHTTPRequestOperation *operation = [self HTTPRequestOperationWithRequest:request success:success failure:failure]; + [self enqueueHTTPRequestOperation:operation]; +} + +- (void)putPath:(NSString *)path + parameters:(NSDictionary *)parameters + success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success + failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure +{ + NSURLRequest *request = [self requestWithMethod:@"PUT" path:path parameters:parameters]; + AFHTTPRequestOperation *operation = [self HTTPRequestOperationWithRequest:request success:success failure:failure]; + [self enqueueHTTPRequestOperation:operation]; +} + +- (void)deletePath:(NSString *)path + parameters:(NSDictionary *)parameters + success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success + failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure +{ + NSURLRequest *request = [self requestWithMethod:@"DELETE" path:path parameters:parameters]; + AFHTTPRequestOperation *operation = [self HTTPRequestOperationWithRequest:request success:success failure:failure]; + [self enqueueHTTPRequestOperation:operation]; +} + +- (void)patchPath:(NSString *)path + parameters:(NSDictionary *)parameters + success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success + failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure +{ + NSURLRequest *request = [self requestWithMethod:@"PATCH" path:path parameters:parameters]; + AFHTTPRequestOperation *operation = [self HTTPRequestOperationWithRequest:request success:success failure:failure]; + [self enqueueHTTPRequestOperation:operation]; +} + +#pragma mark - NSCoding + +- (id)initWithCoder:(NSCoder *)aDecoder { + NSURL *baseURL = [aDecoder decodeObjectForKey:@"baseURL"]; + + self = [self initWithBaseURL:baseURL]; + if (!self) { + return nil; + } + + self.stringEncoding = [aDecoder decodeIntegerForKey:@"stringEncoding"]; + self.parameterEncoding = (AFHTTPClientParameterEncoding) [aDecoder decodeIntegerForKey:@"parameterEncoding"]; + self.registeredHTTPOperationClassNames = [aDecoder decodeObjectForKey:@"registeredHTTPOperationClassNames"]; + self.defaultHeaders = [aDecoder decodeObjectForKey:@"defaultHeaders"]; + + return self; +} + +- (void)encodeWithCoder:(NSCoder *)aCoder { + [aCoder encodeObject:self.baseURL forKey:@"baseURL"]; + [aCoder encodeInteger:(NSInteger)self.stringEncoding forKey:@"stringEncoding"]; + [aCoder encodeInteger:self.parameterEncoding forKey:@"parameterEncoding"]; + [aCoder encodeObject:self.registeredHTTPOperationClassNames forKey:@"registeredHTTPOperationClassNames"]; + [aCoder encodeObject:self.defaultHeaders forKey:@"defaultHeaders"]; +} + +#pragma mark - NSCopying + +- (id)copyWithZone:(NSZone *)zone { + AFHTTPClient *HTTPClient = [[[self class] allocWithZone:zone] initWithBaseURL:self.baseURL]; + + HTTPClient.stringEncoding = self.stringEncoding; + HTTPClient.parameterEncoding = self.parameterEncoding; + HTTPClient.registeredHTTPOperationClassNames = [self.registeredHTTPOperationClassNames mutableCopyWithZone:zone]; + HTTPClient.defaultHeaders = [self.defaultHeaders mutableCopyWithZone:zone]; +#ifdef _SYSTEMCONFIGURATION_H + HTTPClient.networkReachabilityStatusBlock = self.networkReachabilityStatusBlock; +#endif + return HTTPClient; +} + +@end + +#pragma mark - + +static NSString * AFCreateMultipartFormBoundary() { + return [NSString stringWithFormat:@"Boundary+%08X%08X", arc4random(), arc4random()]; +} + +static NSString * const kAFMultipartFormCRLF = @"\r\n"; + +static inline NSString * AFMultipartFormInitialBoundary(NSString *boundary) { + return [NSString stringWithFormat:@"--%@%@", boundary, kAFMultipartFormCRLF]; +} + +static inline NSString * AFMultipartFormEncapsulationBoundary(NSString *boundary) { + return [NSString stringWithFormat:@"%@--%@%@", kAFMultipartFormCRLF, boundary, kAFMultipartFormCRLF]; +} + +static inline NSString * AFMultipartFormFinalBoundary(NSString *boundary) { + return [NSString stringWithFormat:@"%@--%@--%@", kAFMultipartFormCRLF, boundary, kAFMultipartFormCRLF]; +} + +static inline NSString * AFContentTypeForPathExtension(NSString *extension) { +#ifdef __UTTYPE__ + NSString *UTI = (__bridge_transfer NSString *)UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (__bridge CFStringRef)extension, NULL); + NSString *contentType = (__bridge_transfer NSString *)UTTypeCopyPreferredTagWithClass((__bridge CFStringRef)UTI, kUTTagClassMIMEType); + if (!contentType) { + return @"application/octet-stream"; + } else { + return contentType; + } +#else + return @"application/octet-stream"; +#endif +} + +NSUInteger const kAFUploadStream3GSuggestedPacketSize = 1024 * 16; +NSTimeInterval const kAFUploadStream3GSuggestedDelay = 0.2; + +@interface AFHTTPBodyPart : NSObject +@property (nonatomic, assign) NSStringEncoding stringEncoding; +@property (nonatomic, strong) NSDictionary *headers; +@property (nonatomic, strong) id body; +@property (nonatomic, assign) unsigned long long bodyContentLength; +@property (nonatomic, strong) NSInputStream *inputStream; + +@property (nonatomic, copy) NSString *boundary; +@property (nonatomic, assign) BOOL hasInitialBoundary; +@property (nonatomic, assign) BOOL hasFinalBoundary; + +@property (nonatomic, readonly, getter = hasBytesAvailable) BOOL bytesAvailable; +@property (nonatomic, readonly) unsigned long long contentLength; + +- (NSInteger)read:(uint8_t *)buffer + maxLength:(NSUInteger)length; +@end + +@interface AFMultipartBodyStream : NSInputStream +@property (nonatomic, assign) NSUInteger numberOfBytesInPacket; +@property (nonatomic, assign) NSTimeInterval delay; +@property (nonatomic, strong) NSInputStream *inputStream; +@property (nonatomic, readonly) unsigned long long contentLength; +@property (nonatomic, readonly, getter = isEmpty) BOOL empty; + +- (id)initWithStringEncoding:(NSStringEncoding)encoding; +- (void)setInitialAndFinalBoundaries; +- (void)appendHTTPBodyPart:(AFHTTPBodyPart *)bodyPart; +@end + +#pragma mark - + +@interface AFStreamingMultipartFormData () +@property (readwrite, nonatomic, copy) NSMutableURLRequest *request; +@property (nonatomic, copy) NSString *boundary; +@property (readwrite, nonatomic, strong) AFMultipartBodyStream *bodyStream; +@property (readwrite, nonatomic, assign) NSStringEncoding stringEncoding; +@end + +@implementation AFStreamingMultipartFormData +@synthesize request = _request; +@synthesize bodyStream = _bodyStream; +@synthesize stringEncoding = _stringEncoding; + +- (id)initWithURLRequest:(NSMutableURLRequest *)urlRequest + stringEncoding:(NSStringEncoding)encoding +{ + self = [super init]; + if (!self) { + return nil; + } + + self.request = urlRequest; + self.stringEncoding = encoding; + self.boundary = AFCreateMultipartFormBoundary(); + self.bodyStream = [[AFMultipartBodyStream alloc] initWithStringEncoding:encoding]; + + return self; +} + +- (BOOL)appendPartWithFileURL:(NSURL *)fileURL + name:(NSString *)name + error:(NSError * __autoreleasing *)error +{ + NSParameterAssert(fileURL); + NSParameterAssert(name); + + NSString *fileName = [fileURL lastPathComponent]; + NSString *mimeType = AFContentTypeForPathExtension([fileURL pathExtension]); + + return [self appendPartWithFileURL:fileURL name:name fileName:fileName mimeType:mimeType error:error]; +} + +- (BOOL)appendPartWithFileURL:(NSURL *)fileURL + name:(NSString *)name + fileName:(NSString *)fileName + mimeType:(NSString *)mimeType + error:(NSError * __autoreleasing *)error +{ + NSParameterAssert(fileURL); + NSParameterAssert(name); + NSParameterAssert(fileName); + NSParameterAssert(mimeType); + + if (![fileURL isFileURL]) { + NSDictionary *userInfo = [NSDictionary dictionaryWithObject:NSLocalizedStringFromTable(@"Expected URL to be a file URL", @"AFNetworking", nil) forKey:NSLocalizedFailureReasonErrorKey]; + if (error != NULL) { + *error = [[NSError alloc] initWithDomain:AFNetworkingErrorDomain code:NSURLErrorBadURL userInfo:userInfo]; + } + + return NO; + } else if ([fileURL checkResourceIsReachableAndReturnError:error] == NO) { + NSDictionary *userInfo = [NSDictionary dictionaryWithObject:NSLocalizedStringFromTable(@"File URL not reachable.", @"AFNetworking", nil) forKey:NSLocalizedFailureReasonErrorKey]; + if (error != NULL) { + *error = [[NSError alloc] initWithDomain:AFNetworkingErrorDomain code:NSURLErrorBadURL userInfo:userInfo]; + } + + return NO; + } + + NSMutableDictionary *mutableHeaders = [NSMutableDictionary dictionary]; + [mutableHeaders setValue:[NSString stringWithFormat:@"form-data; name=\"%@\"; filename=\"%@\"", name, fileName] forKey:@"Content-Disposition"]; + [mutableHeaders setValue:mimeType forKey:@"Content-Type"]; + + AFHTTPBodyPart *bodyPart = [[AFHTTPBodyPart alloc] init]; + bodyPart.stringEncoding = self.stringEncoding; + bodyPart.headers = mutableHeaders; + bodyPart.boundary = self.boundary; + bodyPart.body = fileURL; + + NSDictionary *fileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:[fileURL path] error:nil]; + bodyPart.bodyContentLength = [[fileAttributes objectForKey:NSFileSize] unsignedLongLongValue]; + + [self.bodyStream appendHTTPBodyPart:bodyPart]; + + return YES; +} + + +- (void)appendPartWithInputStream:(NSInputStream *)inputStream + name:(NSString *)name + fileName:(NSString *)fileName + length:(unsigned long long)length + mimeType:(NSString *)mimeType +{ + NSParameterAssert(name); + NSParameterAssert(fileName); + NSParameterAssert(mimeType); + + NSMutableDictionary *mutableHeaders = [NSMutableDictionary dictionary]; + [mutableHeaders setValue:[NSString stringWithFormat:@"form-data; name=\"%@\"; filename=\"%@\"", name, fileName] forKey:@"Content-Disposition"]; + [mutableHeaders setValue:mimeType forKey:@"Content-Type"]; + + + AFHTTPBodyPart *bodyPart = [[AFHTTPBodyPart alloc] init]; + bodyPart.stringEncoding = self.stringEncoding; + bodyPart.headers = mutableHeaders; + bodyPart.boundary = self.boundary; + bodyPart.body = inputStream; + + bodyPart.bodyContentLength = length; + + [self.bodyStream appendHTTPBodyPart:bodyPart]; +} + +- (void)appendPartWithFileData:(NSData *)data + name:(NSString *)name + fileName:(NSString *)fileName + mimeType:(NSString *)mimeType +{ + NSParameterAssert(name); + NSParameterAssert(fileName); + NSParameterAssert(mimeType); + + NSMutableDictionary *mutableHeaders = [NSMutableDictionary dictionary]; + [mutableHeaders setValue:[NSString stringWithFormat:@"form-data; name=\"%@\"; filename=\"%@\"", name, fileName] forKey:@"Content-Disposition"]; + [mutableHeaders setValue:mimeType forKey:@"Content-Type"]; + + [self appendPartWithHeaders:mutableHeaders body:data]; +} + +- (void)appendPartWithFormData:(NSData *)data + name:(NSString *)name +{ + NSParameterAssert(name); + + NSMutableDictionary *mutableHeaders = [NSMutableDictionary dictionary]; + [mutableHeaders setValue:[NSString stringWithFormat:@"form-data; name=\"%@\"", name] forKey:@"Content-Disposition"]; + + [self appendPartWithHeaders:mutableHeaders body:data]; +} + +- (void)appendPartWithHeaders:(NSDictionary *)headers + body:(NSData *)body +{ + NSParameterAssert(body); + + AFHTTPBodyPart *bodyPart = [[AFHTTPBodyPart alloc] init]; + bodyPart.stringEncoding = self.stringEncoding; + bodyPart.headers = headers; + bodyPart.boundary = self.boundary; + bodyPart.bodyContentLength = [body length]; + bodyPart.body = body; + + [self.bodyStream appendHTTPBodyPart:bodyPart]; +} + +- (void)throttleBandwidthWithPacketSize:(NSUInteger)numberOfBytes + delay:(NSTimeInterval)delay +{ + self.bodyStream.numberOfBytesInPacket = numberOfBytes; + self.bodyStream.delay = delay; +} + +- (NSMutableURLRequest *)requestByFinalizingMultipartFormData { + if ([self.bodyStream isEmpty]) { + return self.request; + } + + // Reset the initial and final boundaries to ensure correct Content-Length + [self.bodyStream setInitialAndFinalBoundaries]; + + [self.request setValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@", self.boundary] forHTTPHeaderField:@"Content-Type"]; + [self.request setValue:[NSString stringWithFormat:@"%llu", [self.bodyStream contentLength]] forHTTPHeaderField:@"Content-Length"]; + [self.request setHTTPBodyStream:self.bodyStream]; + + return self.request; +} + +@end + +#pragma mark - + +@interface AFMultipartBodyStream () +@property (nonatomic, assign) NSStreamStatus streamStatus; +@property (nonatomic, strong) NSError *streamError; +@property (nonatomic, assign) NSStringEncoding stringEncoding; +@property (nonatomic, strong) NSMutableArray *HTTPBodyParts; +@property (nonatomic, strong) NSEnumerator *HTTPBodyPartEnumerator; +@property (nonatomic, strong) AFHTTPBodyPart *currentHTTPBodyPart; +@property (nonatomic, strong) NSOutputStream *outputStream; +@property (nonatomic, strong) NSMutableData *buffer; +@end + +@implementation AFMultipartBodyStream +@synthesize streamStatus = _streamStatus; +@synthesize streamError = _streamError; +@synthesize stringEncoding = _stringEncoding; +@synthesize HTTPBodyParts = _HTTPBodyParts; +@synthesize HTTPBodyPartEnumerator = _HTTPBodyPartEnumerator; +@synthesize currentHTTPBodyPart = _currentHTTPBodyPart; +@synthesize inputStream = _inputStream; +@synthesize outputStream = _outputStream; +@synthesize buffer = _buffer; +@synthesize numberOfBytesInPacket = _numberOfBytesInPacket; +@synthesize delay = _delay; + +- (id)initWithStringEncoding:(NSStringEncoding)encoding { + self = [super init]; + if (!self) { + return nil; + } + + self.stringEncoding = encoding; + self.HTTPBodyParts = [NSMutableArray array]; + self.numberOfBytesInPacket = NSIntegerMax; + + return self; +} + +- (void)setInitialAndFinalBoundaries { + if ([self.HTTPBodyParts count] > 0) { + for (AFHTTPBodyPart *bodyPart in self.HTTPBodyParts) { + bodyPart.hasInitialBoundary = NO; + bodyPart.hasFinalBoundary = NO; + } + + [[self.HTTPBodyParts objectAtIndex:0] setHasInitialBoundary:YES]; + [[self.HTTPBodyParts lastObject] setHasFinalBoundary:YES]; + } +} + +- (void)appendHTTPBodyPart:(AFHTTPBodyPart *)bodyPart { + [self.HTTPBodyParts addObject:bodyPart]; +} + +- (BOOL)isEmpty { + return [self.HTTPBodyParts count] == 0; +} + +#pragma mark - NSInputStream + +- (NSInteger)read:(uint8_t *)buffer + maxLength:(NSUInteger)length +{ + if ([self streamStatus] == NSStreamStatusClosed) { + return 0; + } + + NSInteger totalNumberOfBytesRead = 0; + + while ((NSUInteger)totalNumberOfBytesRead < MIN(length, self.numberOfBytesInPacket)) { + if (!self.currentHTTPBodyPart || ![self.currentHTTPBodyPart hasBytesAvailable]) { + if (!(self.currentHTTPBodyPart = [self.HTTPBodyPartEnumerator nextObject])) { + break; + } + } else { + NSUInteger maxLength = length - (NSUInteger)totalNumberOfBytesRead; + NSInteger numberOfBytesRead = [self.currentHTTPBodyPart read:&buffer[totalNumberOfBytesRead] maxLength:maxLength]; + if (numberOfBytesRead == -1) { + self.streamError = self.currentHTTPBodyPart.inputStream.streamError; + break; + } else { + totalNumberOfBytesRead += numberOfBytesRead; + + if (self.delay > 0.0f) { + [NSThread sleepForTimeInterval:self.delay]; + } + } + } + } + + return totalNumberOfBytesRead; +} + +- (BOOL)getBuffer:(__unused uint8_t **)buffer + length:(__unused NSUInteger *)len +{ + return NO; +} + +- (BOOL)hasBytesAvailable { + return [self streamStatus] == NSStreamStatusOpen; +} + +#pragma mark - NSStream + +- (void)open { + if (self.streamStatus == NSStreamStatusOpen) { + return; + } + + self.streamStatus = NSStreamStatusOpen; + + [self setInitialAndFinalBoundaries]; + self.HTTPBodyPartEnumerator = [self.HTTPBodyParts objectEnumerator]; +} + +- (void)close { + self.streamStatus = NSStreamStatusClosed; +} + +- (id)propertyForKey:(__unused NSString *)key { + return nil; +} + +- (BOOL)setProperty:(__unused id)property + forKey:(__unused NSString *)key +{ + return NO; +} + +- (void)scheduleInRunLoop:(__unused NSRunLoop *)aRunLoop + forMode:(__unused NSString *)mode +{} + +- (void)removeFromRunLoop:(__unused NSRunLoop *)aRunLoop + forMode:(__unused NSString *)mode +{} + +- (unsigned long long)contentLength { + unsigned long long length = 0; + for (AFHTTPBodyPart *bodyPart in self.HTTPBodyParts) { + length += [bodyPart contentLength]; + } + + return length; +} + +#pragma mark - Undocumented CFReadStream Bridged Methods + +- (void)_scheduleInCFRunLoop:(__unused CFRunLoopRef)aRunLoop + forMode:(__unused CFStringRef)aMode +{} + +- (void)_unscheduleFromCFRunLoop:(__unused CFRunLoopRef)aRunLoop + forMode:(__unused CFStringRef)aMode +{} + +- (BOOL)_setCFClientFlags:(__unused CFOptionFlags)inFlags + callback:(__unused CFReadStreamClientCallBack)inCallback + context:(__unused CFStreamClientContext *)inContext { + return NO; +} + +#pragma mark - NSCopying + +-(id)copyWithZone:(NSZone *)zone { + AFMultipartBodyStream *bodyStreamCopy = [[[self class] allocWithZone:zone] initWithStringEncoding:self.stringEncoding]; + + for (AFHTTPBodyPart *bodyPart in self.HTTPBodyParts) { + [bodyStreamCopy appendHTTPBodyPart:[bodyPart copy]]; + } + + [bodyStreamCopy setInitialAndFinalBoundaries]; + + return bodyStreamCopy; +} + +@end + +#pragma mark - + +typedef enum { + AFEncapsulationBoundaryPhase = 1, + AFHeaderPhase = 2, + AFBodyPhase = 3, + AFFinalBoundaryPhase = 4, +} AFHTTPBodyPartReadPhase; + +@interface AFHTTPBodyPart () { + AFHTTPBodyPartReadPhase _phase; + NSInputStream *_inputStream; + unsigned long long _phaseReadOffset; +} + +- (BOOL)transitionToNextPhase; +- (NSInteger)readData:(NSData *)data + intoBuffer:(uint8_t *)buffer + maxLength:(NSUInteger)length; +@end + +@implementation AFHTTPBodyPart +@synthesize stringEncoding = _stringEncoding; +@synthesize headers = _headers; +@synthesize body = _body; +@synthesize bodyContentLength = _bodyContentLength; +@synthesize inputStream = _inputStream; +@synthesize hasInitialBoundary = _hasInitialBoundary; +@synthesize hasFinalBoundary = _hasFinalBoundary; + +- (id)init { + self = [super init]; + if (!self) { + return nil; + } + + [self transitionToNextPhase]; + + return self; +} + +- (void)dealloc { + if (_inputStream) { + [_inputStream close]; + _inputStream = nil; + } +} + +- (NSInputStream *)inputStream { + if (!_inputStream) { + if ([self.body isKindOfClass:[NSData class]]) { + _inputStream = [NSInputStream inputStreamWithData:self.body]; + } else if ([self.body isKindOfClass:[NSURL class]]) { + _inputStream = [NSInputStream inputStreamWithURL:self.body]; + } else if ([self.body isKindOfClass:[NSInputStream class]]) { + _inputStream = self.body; + } + } + + return _inputStream; +} + +- (NSString *)stringForHeaders { + NSMutableString *headerString = [NSMutableString string]; + for (NSString *field in [self.headers allKeys]) { + [headerString appendString:[NSString stringWithFormat:@"%@: %@%@", field, [self.headers valueForKey:field], kAFMultipartFormCRLF]]; + } + [headerString appendString:kAFMultipartFormCRLF]; + + return [NSString stringWithString:headerString]; +} + +- (unsigned long long)contentLength { + unsigned long long length = 0; + + NSData *encapsulationBoundaryData = [([self hasInitialBoundary] ? AFMultipartFormInitialBoundary(self.boundary) : AFMultipartFormEncapsulationBoundary(self.boundary)) dataUsingEncoding:self.stringEncoding]; + length += [encapsulationBoundaryData length]; + + NSData *headersData = [[self stringForHeaders] dataUsingEncoding:self.stringEncoding]; + length += [headersData length]; + + length += _bodyContentLength; + + NSData *closingBoundaryData = ([self hasFinalBoundary] ? [AFMultipartFormFinalBoundary(self.boundary) dataUsingEncoding:self.stringEncoding] : [NSData data]); + length += [closingBoundaryData length]; + + return length; +} + +- (BOOL)hasBytesAvailable { + // Allows `read:maxLength:` to be called again if `AFMultipartFormFinalBoundary` doesn't fit into the available buffer + if (_phase == AFFinalBoundaryPhase) { + return YES; + } + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wcovered-switch-default" + switch (self.inputStream.streamStatus) { + case NSStreamStatusNotOpen: + case NSStreamStatusOpening: + case NSStreamStatusOpen: + case NSStreamStatusReading: + case NSStreamStatusWriting: + return YES; + case NSStreamStatusAtEnd: + case NSStreamStatusClosed: + case NSStreamStatusError: + default: + return NO; + } +#pragma clang diagnostic pop +} + +- (NSInteger)read:(uint8_t *)buffer + maxLength:(NSUInteger)length +{ + NSUInteger totalNumberOfBytesRead = 0; + + if (_phase == AFEncapsulationBoundaryPhase) { + NSData *encapsulationBoundaryData = [([self hasInitialBoundary] ? AFMultipartFormInitialBoundary(self.boundary) : AFMultipartFormEncapsulationBoundary(self.boundary)) dataUsingEncoding:self.stringEncoding]; + totalNumberOfBytesRead += [self readData:encapsulationBoundaryData intoBuffer:&buffer[totalNumberOfBytesRead] maxLength:(length - (NSUInteger)totalNumberOfBytesRead)]; + } + + if (_phase == AFHeaderPhase) { + NSData *headersData = [[self stringForHeaders] dataUsingEncoding:self.stringEncoding]; + totalNumberOfBytesRead += [self readData:headersData intoBuffer:&buffer[totalNumberOfBytesRead] maxLength:(length - (NSUInteger)totalNumberOfBytesRead)]; + } + + if (_phase == AFBodyPhase) { + NSInteger numberOfBytesRead = 0; + + numberOfBytesRead = [self.inputStream read:&buffer[totalNumberOfBytesRead] maxLength:(length - (NSUInteger)totalNumberOfBytesRead)]; + if (numberOfBytesRead == -1) { + return -1; + } else { + totalNumberOfBytesRead += numberOfBytesRead; + + if ([self.inputStream streamStatus] >= NSStreamStatusAtEnd) { + [self transitionToNextPhase]; + } + } + } + + if (_phase == AFFinalBoundaryPhase) { + NSData *closingBoundaryData = ([self hasFinalBoundary] ? [AFMultipartFormFinalBoundary(self.boundary) dataUsingEncoding:self.stringEncoding] : [NSData data]); + totalNumberOfBytesRead += [self readData:closingBoundaryData intoBuffer:&buffer[totalNumberOfBytesRead] maxLength:(length - (NSUInteger)totalNumberOfBytesRead)]; + } + + return totalNumberOfBytesRead; +} + +- (NSInteger)readData:(NSData *)data + intoBuffer:(uint8_t *)buffer + maxLength:(NSUInteger)length +{ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wgnu" + NSRange range = NSMakeRange((NSUInteger)_phaseReadOffset, MIN([data length] - ((NSUInteger)_phaseReadOffset), length)); + [data getBytes:buffer range:range]; +#pragma clang diagnostic pop + + _phaseReadOffset += range.length; + + if (((NSUInteger)_phaseReadOffset) >= [data length]) { + [self transitionToNextPhase]; + } + + return (NSInteger)range.length; +} + +- (BOOL)transitionToNextPhase { + if (![[NSThread currentThread] isMainThread]) { + [self performSelectorOnMainThread:@selector(transitionToNextPhase) withObject:nil waitUntilDone:YES]; + return YES; + } + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wcovered-switch-default" + switch (_phase) { + case AFEncapsulationBoundaryPhase: + _phase = AFHeaderPhase; + break; + case AFHeaderPhase: + [self.inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes]; + [self.inputStream open]; + _phase = AFBodyPhase; + break; + case AFBodyPhase: + [self.inputStream close]; + _phase = AFFinalBoundaryPhase; + break; + case AFFinalBoundaryPhase: + default: + _phase = AFEncapsulationBoundaryPhase; + break; + } + _phaseReadOffset = 0; +#pragma clang diagnostic pop + + return YES; +} + +#pragma mark - NSCopying + +- (id)copyWithZone:(NSZone *)zone { + AFHTTPBodyPart *bodyPart = [[[self class] allocWithZone:zone] init]; + + bodyPart.stringEncoding = self.stringEncoding; + bodyPart.headers = self.headers; + bodyPart.bodyContentLength = self.bodyContentLength; + bodyPart.body = self.body; + + return bodyPart; +} + +@end diff --git a/Pods/AFNetworking/AFNetworking/AFHTTPRequestOperation.h b/Pods/AFNetworking/AFNetworking/AFHTTPRequestOperation.h new file mode 100644 index 0000000..b40e3d5 --- /dev/null +++ b/Pods/AFNetworking/AFNetworking/AFHTTPRequestOperation.h @@ -0,0 +1,133 @@ +// AFHTTPRequestOperation.h +// +// Copyright (c) 2011 Gowalla (http://gowalla.com/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "AFURLConnectionOperation.h" + +/** + `AFHTTPRequestOperation` is a subclass of `AFURLConnectionOperation` for requests using the HTTP or HTTPS protocols. It encapsulates the concept of acceptable status codes and content types, which determine the success or failure of a request. + */ +@interface AFHTTPRequestOperation : AFURLConnectionOperation + +///---------------------------------------------- +/// @name Getting HTTP URL Connection Information +///---------------------------------------------- + +/** + The last HTTP response received by the operation's connection. + */ +@property (readonly, nonatomic, strong) NSHTTPURLResponse *response; + +///---------------------------------------------------------- +/// @name Managing And Checking For Acceptable HTTP Responses +///---------------------------------------------------------- + +/** + A Boolean value that corresponds to whether the status code of the response is within the specified set of acceptable status codes. Returns `YES` if `acceptableStatusCodes` is `nil`. + */ +@property (nonatomic, readonly) BOOL hasAcceptableStatusCode; + +/** + A Boolean value that corresponds to whether the MIME type of the response is among the specified set of acceptable content types. Returns `YES` if `acceptableContentTypes` is `nil`. + */ +@property (nonatomic, readonly) BOOL hasAcceptableContentType; + +/** + The callback dispatch queue on success. If `NULL` (default), the main queue is used. + */ +@property (nonatomic, assign) dispatch_queue_t successCallbackQueue; + +/** + The callback dispatch queue on failure. If `NULL` (default), the main queue is used. + */ +@property (nonatomic, assign) dispatch_queue_t failureCallbackQueue; + +///------------------------------------------------------------ +/// @name Managing Acceptable HTTP Status Codes & Content Types +///------------------------------------------------------------ + +/** + Returns an `NSIndexSet` object containing the ranges of acceptable HTTP status codes. When non-`nil`, the operation will set the `error` property to an error in `AFErrorDomain`. See http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html + + By default, this is the range 200 to 299, inclusive. + */ ++ (NSIndexSet *)acceptableStatusCodes; + +/** + Adds status codes to the set of acceptable HTTP status codes returned by `+acceptableStatusCodes` in subsequent calls by this class and its descendants. + + @param statusCodes The status codes to be added to the set of acceptable HTTP status codes + */ ++ (void)addAcceptableStatusCodes:(NSIndexSet *)statusCodes; + +/** + Returns an `NSSet` object containing the acceptable MIME types. When non-`nil`, the operation will set the `error` property to an error in `AFErrorDomain`. See http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.17 + + By default, this is `nil`. + */ ++ (NSSet *)acceptableContentTypes; + +/** + Adds content types to the set of acceptable MIME types returned by `+acceptableContentTypes` in subsequent calls by this class and its descendants. + + @param contentTypes The content types to be added to the set of acceptable MIME types + */ ++ (void)addAcceptableContentTypes:(NSSet *)contentTypes; + + +///----------------------------------------------------- +/// @name Determining Whether A Request Can Be Processed +///----------------------------------------------------- + +/** + A Boolean value determining whether or not the class can process the specified request. For example, `AFJSONRequestOperation` may check to make sure the content type was `application/json` or the URL path extension was `.json`. + + @param urlRequest The request that is determined to be supported or not supported for this class. + */ ++ (BOOL)canProcessRequest:(NSURLRequest *)urlRequest; + +///----------------------------------------------------------- +/// @name Setting Completion Block Success / Failure Callbacks +///----------------------------------------------------------- + +/** + Sets the `completionBlock` property with a block that executes either the specified success or failure block, depending on the state of the request on completion. If `error` returns a value, which can be caused by an unacceptable status code or content type, then `failure` is executed. Otherwise, `success` is executed. + + This method should be overridden in subclasses in order to specify the response object passed into the success block. + + @param success The block to be executed on the completion of a successful request. This block has no return value and takes two arguments: the receiver operation and the object constructed from the response data of the request. + @param failure The block to be executed on the completion of an unsuccessful request. This block has no return value and takes two arguments: the receiver operation and the error that occurred during the request. + */ +- (void)setCompletionBlockWithSuccess:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success + failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure; + +@end + +///---------------- +/// @name Functions +///---------------- + +/** + Returns a set of MIME types detected in an HTTP `Accept` or `Content-Type` header. + */ +extern NSSet * AFContentTypesFromHTTPHeader(NSString *string); + diff --git a/Pods/AFNetworking/AFNetworking/AFHTTPRequestOperation.m b/Pods/AFNetworking/AFNetworking/AFHTTPRequestOperation.m new file mode 100644 index 0000000..940b6e7 --- /dev/null +++ b/Pods/AFNetworking/AFNetworking/AFHTTPRequestOperation.m @@ -0,0 +1,327 @@ +// AFHTTPRequestOperation.m +// +// Copyright (c) 2011 Gowalla (http://gowalla.com/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "AFHTTPRequestOperation.h" +#import + +// Workaround for change in imp_implementationWithBlock() with Xcode 4.5 +#if defined(__IPHONE_6_0) || defined(__MAC_10_8) +#define AF_CAST_TO_BLOCK id +#else +#define AF_CAST_TO_BLOCK __bridge void * +#endif + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wstrict-selector-match" + +NSSet * AFContentTypesFromHTTPHeader(NSString *string) { + if (!string) { + return nil; + } + + NSArray *mediaRanges = [string componentsSeparatedByString:@","]; + NSMutableSet *mutableContentTypes = [NSMutableSet setWithCapacity:mediaRanges.count]; + + [mediaRanges enumerateObjectsUsingBlock:^(NSString *mediaRange, __unused NSUInteger idx, __unused BOOL *stop) { + NSRange parametersRange = [mediaRange rangeOfString:@";"]; + if (parametersRange.location != NSNotFound) { + mediaRange = [mediaRange substringToIndex:parametersRange.location]; + } + + mediaRange = [mediaRange stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; + + if (mediaRange.length > 0) { + [mutableContentTypes addObject:mediaRange]; + } + }]; + + return [NSSet setWithSet:mutableContentTypes]; +} + +static void AFGetMediaTypeAndSubtypeWithString(NSString *string, NSString **type, NSString **subtype) { + if (!string) { + return; + } + + NSScanner *scanner = [NSScanner scannerWithString:string]; + [scanner setCharactersToBeSkipped:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; + [scanner scanUpToString:@"/" intoString:type]; + [scanner scanString:@"/" intoString:nil]; + [scanner scanUpToString:@";" intoString:subtype]; +} + +static NSString * AFStringFromIndexSet(NSIndexSet *indexSet) { + NSMutableString *string = [NSMutableString string]; + + NSRange range = NSMakeRange([indexSet firstIndex], 1); + while (range.location != NSNotFound) { + NSUInteger nextIndex = [indexSet indexGreaterThanIndex:range.location]; + while (nextIndex == range.location + range.length) { + range.length++; + nextIndex = [indexSet indexGreaterThanIndex:nextIndex]; + } + + if (string.length) { + [string appendString:@","]; + } + + if (range.length == 1) { + [string appendFormat:@"%lu", (long)range.location]; + } else { + NSUInteger firstIndex = range.location; + NSUInteger lastIndex = firstIndex + range.length - 1; + [string appendFormat:@"%lu-%lu", (long)firstIndex, (long)lastIndex]; + } + + range.location = nextIndex; + range.length = 1; + } + + return string; +} + +static void AFSwizzleClassMethodWithClassAndSelectorUsingBlock(Class klass, SEL selector, id block) { + Method originalMethod = class_getClassMethod(klass, selector); + IMP implementation = imp_implementationWithBlock((AF_CAST_TO_BLOCK)block); + class_replaceMethod(objc_getMetaClass([NSStringFromClass(klass) UTF8String]), selector, implementation, method_getTypeEncoding(originalMethod)); +} + +#pragma mark - + +@interface AFHTTPRequestOperation () +@property (readwrite, nonatomic, strong) NSURLRequest *request; +@property (readwrite, nonatomic, strong) NSHTTPURLResponse *response; +@property (readwrite, nonatomic, strong) NSError *HTTPError; +@property (readwrite, nonatomic, strong) NSRecursiveLock *lock; +@end + +@implementation AFHTTPRequestOperation +@synthesize HTTPError = _HTTPError; +@synthesize successCallbackQueue = _successCallbackQueue; +@synthesize failureCallbackQueue = _failureCallbackQueue; +@dynamic lock; +@dynamic request; +@dynamic response; + +- (void)dealloc { + if (_successCallbackQueue) { +#if !OS_OBJECT_USE_OBJC + dispatch_release(_successCallbackQueue); +#endif + _successCallbackQueue = NULL; + } + + if (_failureCallbackQueue) { +#if !OS_OBJECT_USE_OBJC + dispatch_release(_failureCallbackQueue); +#endif + _failureCallbackQueue = NULL; + } +} + +- (NSError *)error { + [self.lock lock]; + if (!self.HTTPError && self.response) { + if (![self hasAcceptableStatusCode] || ![self hasAcceptableContentType]) { + NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; + [userInfo setValue:self.responseString forKey:NSLocalizedRecoverySuggestionErrorKey]; + [userInfo setValue:[self.request URL] forKey:NSURLErrorFailingURLErrorKey]; + [userInfo setValue:self.request forKey:AFNetworkingOperationFailingURLRequestErrorKey]; + [userInfo setValue:self.response forKey:AFNetworkingOperationFailingURLResponseErrorKey]; + + if (![self hasAcceptableStatusCode]) { + NSInteger statusCode = ([self.response isKindOfClass:[NSHTTPURLResponse class]]) ? [self.response statusCode] : 200; + [userInfo setValue:[NSString stringWithFormat:NSLocalizedStringFromTable(@"Expected status code in (%@), got %ld", @"AFNetworking", nil), AFStringFromIndexSet([[self class] acceptableStatusCodes]), (long)statusCode] forKey:NSLocalizedDescriptionKey]; + self.HTTPError = [[NSError alloc] initWithDomain:AFNetworkingErrorDomain code:NSURLErrorBadServerResponse userInfo:userInfo]; + } else if (![self hasAcceptableContentType]) { + // Don't invalidate content type if there is no content + if ([self.responseData length] > 0) { + [userInfo setValue:[NSString stringWithFormat:NSLocalizedStringFromTable(@"Expected content type %@, got %@", @"AFNetworking", nil), [[self class] acceptableContentTypes], [self.response MIMEType]] forKey:NSLocalizedDescriptionKey]; + self.HTTPError = [[NSError alloc] initWithDomain:AFNetworkingErrorDomain code:NSURLErrorCannotDecodeContentData userInfo:userInfo]; + } + } + } + } + [self.lock unlock]; + + if (self.HTTPError) { + return self.HTTPError; + } else { + return [super error]; + } +} + +- (NSStringEncoding)responseStringEncoding { + // When no explicit charset parameter is provided by the sender, media subtypes of the "text" type are defined to have a default charset value of "ISO-8859-1" when received via HTTP. Data in character sets other than "ISO-8859-1" or its subsets MUST be labeled with an appropriate charset value. + // See http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.4.1 + if (self.response && !self.response.textEncodingName && self.responseData && [self.response respondsToSelector:@selector(allHeaderFields)]) { + NSString *type = nil; + AFGetMediaTypeAndSubtypeWithString([[self.response allHeaderFields] valueForKey:@"Content-Type"], &type, nil); + + if ([type isEqualToString:@"text"]) { + return NSISOLatin1StringEncoding; + } + } + + return [super responseStringEncoding]; +} + +- (void)pause { + unsigned long long offset = 0; + if ([self.outputStream propertyForKey:NSStreamFileCurrentOffsetKey]) { + offset = [[self.outputStream propertyForKey:NSStreamFileCurrentOffsetKey] unsignedLongLongValue]; + } else { + offset = [[self.outputStream propertyForKey:NSStreamDataWrittenToMemoryStreamKey] length]; + } + + NSMutableURLRequest *mutableURLRequest = [self.request mutableCopy]; + if ([self.response respondsToSelector:@selector(allHeaderFields)] && [[self.response allHeaderFields] valueForKey:@"ETag"]) { + [mutableURLRequest setValue:[[self.response allHeaderFields] valueForKey:@"ETag"] forHTTPHeaderField:@"If-Range"]; + } + [mutableURLRequest setValue:[NSString stringWithFormat:@"bytes=%llu-", offset] forHTTPHeaderField:@"Range"]; + self.request = mutableURLRequest; + + [super pause]; +} + +- (BOOL)hasAcceptableStatusCode { + if (!self.response) { + return NO; + } + + NSUInteger statusCode = ([self.response isKindOfClass:[NSHTTPURLResponse class]]) ? (NSUInteger)[self.response statusCode] : 200; + return ![[self class] acceptableStatusCodes] || [[[self class] acceptableStatusCodes] containsIndex:statusCode]; +} + +- (BOOL)hasAcceptableContentType { + if (!self.response) { + return NO; + } + + // Any HTTP/1.1 message containing an entity-body SHOULD include a Content-Type header field defining the media type of that body. If and only if the media type is not given by a Content-Type field, the recipient MAY attempt to guess the media type via inspection of its content and/or the name extension(s) of the URI used to identify the resource. If the media type remains unknown, the recipient SHOULD treat it as type "application/octet-stream". + // See http://www.w3.org/Protocols/rfc2616/rfc2616-sec7.html + NSString *contentType = [self.response MIMEType]; + if (!contentType) { + contentType = @"application/octet-stream"; + } + + return ![[self class] acceptableContentTypes] || [[[self class] acceptableContentTypes] containsObject:contentType]; +} + +- (void)setSuccessCallbackQueue:(dispatch_queue_t)successCallbackQueue { + if (successCallbackQueue != _successCallbackQueue) { + if (_successCallbackQueue) { +#if !OS_OBJECT_USE_OBJC + dispatch_release(_successCallbackQueue); +#endif + _successCallbackQueue = NULL; + } + + if (successCallbackQueue) { +#if !OS_OBJECT_USE_OBJC + dispatch_retain(successCallbackQueue); +#endif + _successCallbackQueue = successCallbackQueue; + } + } +} + +- (void)setFailureCallbackQueue:(dispatch_queue_t)failureCallbackQueue { + if (failureCallbackQueue != _failureCallbackQueue) { + if (_failureCallbackQueue) { +#if !OS_OBJECT_USE_OBJC + dispatch_release(_failureCallbackQueue); +#endif + _failureCallbackQueue = NULL; + } + + if (failureCallbackQueue) { +#if !OS_OBJECT_USE_OBJC + dispatch_retain(failureCallbackQueue); +#endif + _failureCallbackQueue = failureCallbackQueue; + } + } +} + +- (void)setCompletionBlockWithSuccess:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success + failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure +{ + // completionBlock is manually nilled out in AFURLConnectionOperation to break the retain cycle. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warc-retain-cycles" +#pragma clang diagnostic ignored "-Wgnu" + self.completionBlock = ^{ + if (self.error) { + if (failure) { + dispatch_async(self.failureCallbackQueue ?: dispatch_get_main_queue(), ^{ + failure(self, self.error); + }); + } + } else { + if (success) { + dispatch_async(self.successCallbackQueue ?: dispatch_get_main_queue(), ^{ + success(self, self.responseData); + }); + } + } + }; +#pragma clang diagnostic pop +} + +#pragma mark - AFHTTPRequestOperation + ++ (NSIndexSet *)acceptableStatusCodes { + return [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(200, 100)]; +} + ++ (void)addAcceptableStatusCodes:(NSIndexSet *)statusCodes { + NSMutableIndexSet *mutableStatusCodes = [[NSMutableIndexSet alloc] initWithIndexSet:[self acceptableStatusCodes]]; + [mutableStatusCodes addIndexes:statusCodes]; + AFSwizzleClassMethodWithClassAndSelectorUsingBlock([self class], @selector(acceptableStatusCodes), ^(__unused id _self) { + return mutableStatusCodes; + }); +} + ++ (NSSet *)acceptableContentTypes { + return nil; +} + ++ (void)addAcceptableContentTypes:(NSSet *)contentTypes { + NSMutableSet *mutableContentTypes = [[NSMutableSet alloc] initWithSet:[self acceptableContentTypes] copyItems:YES]; + [mutableContentTypes unionSet:contentTypes]; + AFSwizzleClassMethodWithClassAndSelectorUsingBlock([self class], @selector(acceptableContentTypes), ^(__unused id _self) { + return mutableContentTypes; + }); +} + ++ (BOOL)canProcessRequest:(NSURLRequest *)request { + if ([[self class] isEqual:[AFHTTPRequestOperation class]]) { + return YES; + } + + return [[self acceptableContentTypes] intersectsSet:AFContentTypesFromHTTPHeader([request valueForHTTPHeaderField:@"Accept"])]; +} + +@end + +#pragma clang diagnostic pop diff --git a/Pods/AFNetworking/AFNetworking/AFImageRequestOperation.h b/Pods/AFNetworking/AFNetworking/AFImageRequestOperation.h new file mode 100644 index 0000000..d5e6596 --- /dev/null +++ b/Pods/AFNetworking/AFNetworking/AFImageRequestOperation.h @@ -0,0 +1,113 @@ +// AFImageRequestOperation.h +// +// Copyright (c) 2011 Gowalla (http://gowalla.com/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "AFHTTPRequestOperation.h" + +#import + +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) +#import +#elif defined(__MAC_OS_X_VERSION_MIN_REQUIRED) +#import +#endif + +/** + `AFImageRequestOperation` is a subclass of `AFHTTPRequestOperation` for downloading and processing images. + + ## Acceptable Content Types + + By default, `AFImageRequestOperation` accepts the following MIME types, which correspond to the image formats supported by UIImage or NSImage: + + - `image/tiff` + - `image/jpeg` + - `image/gif` + - `image/png` + - `image/ico` + - `image/x-icon` + - `image/bmp` + - `image/x-bmp` + - `image/x-xbitmap` + - `image/x-win-bitmap` + */ +@interface AFImageRequestOperation : AFHTTPRequestOperation + +/** + An image constructed from the response data. If an error occurs during the request, `nil` will be returned, and the `error` property will be set to the error. + */ +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) +@property (readonly, nonatomic, strong) UIImage *responseImage; +#elif defined(__MAC_OS_X_VERSION_MIN_REQUIRED) +@property (readonly, nonatomic, strong) NSImage *responseImage; +#endif + +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) +/** + The scale factor used when interpreting the image data to construct `responseImage`. Specifying a scale factor of 1.0 results in an image whose size matches the pixel-based dimensions of the image. Applying a different scale factor changes the size of the image as reported by the size property. This is set to the value of scale of the main screen by default, which automatically scales images for retina displays, for instance. + */ +@property (nonatomic, assign) CGFloat imageScale; + +/** + Whether to automatically inflate response image data for compressed formats (such as PNG or JPEG). Enabling this can significantly improve drawing performance on iOS when used with `setCompletionBlockWithSuccess:failure:`, as it allows a bitmap representation to be constructed in the background rather than on the main thread. `YES` by default. + */ +@property (nonatomic, assign) BOOL automaticallyInflatesResponseImage; +#endif + +/** + Creates and returns an `AFImageRequestOperation` object and sets the specified success callback. + + @param urlRequest The request object to be loaded asynchronously during execution of the operation. + @param success A block object to be executed when the request finishes successfully. This block has no return value and takes a single argument, the image created from the response data of the request. + + @return A new image request operation + */ +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) ++ (instancetype)imageRequestOperationWithRequest:(NSURLRequest *)urlRequest + success:(void (^)(UIImage *image))success; +#elif defined(__MAC_OS_X_VERSION_MIN_REQUIRED) ++ (instancetype)imageRequestOperationWithRequest:(NSURLRequest *)urlRequest + success:(void (^)(NSImage *image))success; +#endif + +/** + Creates and returns an `AFImageRequestOperation` object and sets the specified success callback. + + @param urlRequest The request object to be loaded asynchronously during execution of the operation. + @param imageProcessingBlock A block object to be executed after the image request finishes successfully, but before the image is returned in the `success` block. This block takes a single argument, the image loaded from the response body, and returns the processed image. + @param success A block object to be executed when the request finishes successfully, with a status code in the 2xx range, and with an acceptable content type (e.g. `image/png`). This block has no return value and takes three arguments: the request object of the operation, the response for the request, and the image created from the response data. + @param failure A block object to be executed when the request finishes unsuccessfully. This block has no return value and takes three arguments: the request object of the operation, the response for the request, and the error associated with the cause for the unsuccessful operation. + + @return A new image request operation + */ +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) ++ (instancetype)imageRequestOperationWithRequest:(NSURLRequest *)urlRequest + imageProcessingBlock:(UIImage *(^)(UIImage *image))imageProcessingBlock + success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image))success + failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error))failure; +#elif defined(__MAC_OS_X_VERSION_MIN_REQUIRED) ++ (instancetype)imageRequestOperationWithRequest:(NSURLRequest *)urlRequest + imageProcessingBlock:(NSImage *(^)(NSImage *image))imageProcessingBlock + success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSImage *image))success + failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error))failure; +#endif + +@end diff --git a/Pods/AFNetworking/AFNetworking/AFImageRequestOperation.m b/Pods/AFNetworking/AFNetworking/AFImageRequestOperation.m new file mode 100644 index 0000000..7023b37 --- /dev/null +++ b/Pods/AFNetworking/AFNetworking/AFImageRequestOperation.m @@ -0,0 +1,321 @@ +// AFImageRequestOperation.m +// +// Copyright (c) 2011 Gowalla (http://gowalla.com/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "AFImageRequestOperation.h" + +static dispatch_queue_t image_request_operation_processing_queue() { + static dispatch_queue_t af_image_request_operation_processing_queue; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + af_image_request_operation_processing_queue = dispatch_queue_create("com.alamofire.networking.image-request.processing", DISPATCH_QUEUE_CONCURRENT); + }); + + return af_image_request_operation_processing_queue; +} + +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) +#import + +static UIImage * AFImageWithDataAtScale(NSData *data, CGFloat scale) { + UIImage *image = [[UIImage alloc] initWithData:data]; + + return [[UIImage alloc] initWithCGImage:[image CGImage] scale:scale orientation:image.imageOrientation]; +} + +static UIImage * AFInflatedImageFromResponseWithDataAtScale(NSHTTPURLResponse *response, NSData *data, CGFloat scale) { + if (!data || [data length] == 0) { + return nil; + } + + UIImage *image = AFImageWithDataAtScale(data, scale); + if (image.images) { + return image; + } + + CGImageRef imageRef = nil; + CGDataProviderRef dataProvider = CGDataProviderCreateWithCFData((__bridge CFDataRef)data); + + if ([response.MIMEType isEqualToString:@"image/png"]) { + imageRef = CGImageCreateWithPNGDataProvider(dataProvider, NULL, true, kCGRenderingIntentDefault); + } else if ([response.MIMEType isEqualToString:@"image/jpeg"]) { + imageRef = CGImageCreateWithJPEGDataProvider(dataProvider, NULL, true, kCGRenderingIntentDefault); + } + + if (!imageRef) { + imageRef = CGImageCreateCopy([image CGImage]); + + if (!imageRef) { + CGDataProviderRelease(dataProvider); + return image; + } + } + + CGDataProviderRelease(dataProvider); + + size_t width = CGImageGetWidth(imageRef); + size_t height = CGImageGetHeight(imageRef); + size_t bitsPerComponent = CGImageGetBitsPerComponent(imageRef); + size_t bytesPerRow = 0; // CGImageGetBytesPerRow() calculates incorrectly in iOS 5.0, so defer to CGBitmapContextCreate() + CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); + CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(imageRef); + + if (CGColorSpaceGetNumberOfComponents(colorSpace) == 3) { + int alpha = (bitmapInfo & kCGBitmapAlphaInfoMask); + if (alpha == kCGImageAlphaNone) { + bitmapInfo &= ~kCGBitmapAlphaInfoMask; + bitmapInfo |= kCGImageAlphaNoneSkipFirst; + } else if (!(alpha == kCGImageAlphaNoneSkipFirst || alpha == kCGImageAlphaNoneSkipLast)) { + bitmapInfo &= ~kCGBitmapAlphaInfoMask; + bitmapInfo |= kCGImageAlphaPremultipliedFirst; + } + } + + CGContextRef context = CGBitmapContextCreate(NULL, width, height, bitsPerComponent, bytesPerRow, colorSpace, bitmapInfo); + + CGColorSpaceRelease(colorSpace); + + if (!context) { + CGImageRelease(imageRef); + + return image; + } + + CGRect rect = CGRectMake(0.0f, 0.0f, width, height); + CGContextDrawImage(context, rect, imageRef); + CGImageRef inflatedImageRef = CGBitmapContextCreateImage(context); + CGContextRelease(context); + + UIImage *inflatedImage = [[UIImage alloc] initWithCGImage:inflatedImageRef scale:scale orientation:image.imageOrientation]; + CGImageRelease(inflatedImageRef); + CGImageRelease(imageRef); + + return inflatedImage; +} +#endif + +@interface AFImageRequestOperation () +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) +@property (readwrite, nonatomic, strong) UIImage *responseImage; +#elif defined(__MAC_OS_X_VERSION_MIN_REQUIRED) +@property (readwrite, nonatomic, strong) NSImage *responseImage; +#endif +@end + +@implementation AFImageRequestOperation +@synthesize responseImage = _responseImage; +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) +@synthesize imageScale = _imageScale; +#endif + +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) ++ (instancetype)imageRequestOperationWithRequest:(NSURLRequest *)urlRequest + success:(void (^)(UIImage *image))success +{ + return [self imageRequestOperationWithRequest:urlRequest imageProcessingBlock:nil success:^(NSURLRequest __unused *request, NSHTTPURLResponse __unused *response, UIImage *image) { + if (success) { + success(image); + } + } failure:nil]; +} +#elif defined(__MAC_OS_X_VERSION_MIN_REQUIRED) ++ (instancetype)imageRequestOperationWithRequest:(NSURLRequest *)urlRequest + success:(void (^)(NSImage *image))success +{ + return [self imageRequestOperationWithRequest:urlRequest imageProcessingBlock:nil success:^(NSURLRequest __unused *request, NSHTTPURLResponse __unused *response, NSImage *image) { + if (success) { + success(image); + } + } failure:nil]; +} +#endif + + +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) ++ (instancetype)imageRequestOperationWithRequest:(NSURLRequest *)urlRequest + imageProcessingBlock:(UIImage *(^)(UIImage *))imageProcessingBlock + success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image))success + failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error))failure +{ + AFImageRequestOperation *requestOperation = [(AFImageRequestOperation *)[self alloc] initWithRequest:urlRequest]; + [requestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) { + if (success) { + UIImage *image = responseObject; + if (imageProcessingBlock) { + dispatch_async(image_request_operation_processing_queue(), ^(void) { + UIImage *processedImage = imageProcessingBlock(image); +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wgnu" + dispatch_async(operation.successCallbackQueue ?: dispatch_get_main_queue(), ^(void) { + success(operation.request, operation.response, processedImage); + }); +#pragma clang diagnostic pop + }); + } else { + success(operation.request, operation.response, image); + } + } + } failure:^(AFHTTPRequestOperation *operation, NSError *error) { + if (failure) { + failure(operation.request, operation.response, error); + } + }]; + + + return requestOperation; +} +#elif defined(__MAC_OS_X_VERSION_MIN_REQUIRED) ++ (instancetype)imageRequestOperationWithRequest:(NSURLRequest *)urlRequest + imageProcessingBlock:(NSImage *(^)(NSImage *))imageProcessingBlock + success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSImage *image))success + failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error))failure +{ + AFImageRequestOperation *requestOperation = [(AFImageRequestOperation *)[self alloc] initWithRequest:urlRequest]; + [requestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) { + if (success) { + NSImage *image = responseObject; + if (imageProcessingBlock) { + dispatch_async(image_request_operation_processing_queue(), ^(void) { + NSImage *processedImage = imageProcessingBlock(image); + + dispatch_async(operation.successCallbackQueue ?: dispatch_get_main_queue(), ^(void) { + success(operation.request, operation.response, processedImage); + }); + }); + } else { + success(operation.request, operation.response, image); + } + } + } failure:^(AFHTTPRequestOperation *operation, NSError *error) { + if (failure) { + failure(operation.request, operation.response, error); + } + }]; + + return requestOperation; +} +#endif + +- (id)initWithRequest:(NSURLRequest *)urlRequest { + self = [super initWithRequest:urlRequest]; + if (!self) { + return nil; + } + +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) + self.imageScale = [[UIScreen mainScreen] scale]; + self.automaticallyInflatesResponseImage = YES; +#endif + + return self; +} + + +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) +- (UIImage *)responseImage { + if (!_responseImage && [self.responseData length] > 0 && [self isFinished]) { + if (self.automaticallyInflatesResponseImage) { + self.responseImage = AFInflatedImageFromResponseWithDataAtScale(self.response, self.responseData, self.imageScale); + } else { + self.responseImage = AFImageWithDataAtScale(self.responseData, self.imageScale); + } + } + + return _responseImage; +} + +- (void)setImageScale:(CGFloat)imageScale { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wfloat-equal" + if (imageScale == _imageScale) { + return; + } +#pragma clang diagnostic pop + + _imageScale = imageScale; + + self.responseImage = nil; +} +#elif defined(__MAC_OS_X_VERSION_MIN_REQUIRED) +- (NSImage *)responseImage { + if (!_responseImage && [self.responseData length] > 0 && [self isFinished]) { + // Ensure that the image is set to it's correct pixel width and height + NSBitmapImageRep *bitimage = [[NSBitmapImageRep alloc] initWithData:self.responseData]; + self.responseImage = [[NSImage alloc] initWithSize:NSMakeSize([bitimage pixelsWide], [bitimage pixelsHigh])]; + [self.responseImage addRepresentation:bitimage]; + } + + return _responseImage; +} +#endif + +#pragma mark - AFHTTPRequestOperation + ++ (NSSet *)acceptableContentTypes { + return [NSSet setWithObjects:@"image/tiff", @"image/jpeg", @"image/gif", @"image/png", @"image/ico", @"image/x-icon", @"image/bmp", @"image/x-bmp", @"image/x-xbitmap", @"image/x-win-bitmap", nil]; +} + ++ (BOOL)canProcessRequest:(NSURLRequest *)request { + static NSSet * _acceptablePathExtension = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + _acceptablePathExtension = [[NSSet alloc] initWithObjects:@"tif", @"tiff", @"jpg", @"jpeg", @"gif", @"png", @"ico", @"bmp", @"cur", nil]; + }); + + return [_acceptablePathExtension containsObject:[[request URL] pathExtension]] || [super canProcessRequest:request]; +} + +- (void)setCompletionBlockWithSuccess:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success + failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure +{ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warc-retain-cycles" +#pragma clang diagnostic ignored "-Wgnu" + + self.completionBlock = ^ { + dispatch_async(image_request_operation_processing_queue(), ^(void) { + if (self.error) { + if (failure) { + dispatch_async(self.failureCallbackQueue ?: dispatch_get_main_queue(), ^{ + failure(self, self.error); + }); + } + } else { + if (success) { +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) + UIImage *image = nil; +#elif defined(__MAC_OS_X_VERSION_MIN_REQUIRED) + NSImage *image = nil; +#endif + + image = self.responseImage; + + dispatch_async(self.successCallbackQueue ?: dispatch_get_main_queue(), ^{ + success(self, image); + }); + } + } + }); + }; +#pragma clang diagnostic pop +} + +@end diff --git a/Pods/AFNetworking/AFNetworking/AFJSONRequestOperation.h b/Pods/AFNetworking/AFNetworking/AFJSONRequestOperation.h new file mode 100644 index 0000000..5493a40 --- /dev/null +++ b/Pods/AFNetworking/AFNetworking/AFJSONRequestOperation.h @@ -0,0 +1,71 @@ +// AFJSONRequestOperation.h +// +// Copyright (c) 2011 Gowalla (http://gowalla.com/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "AFHTTPRequestOperation.h" + +/** + `AFJSONRequestOperation` is a subclass of `AFHTTPRequestOperation` for downloading and working with JSON response data. + + ## Acceptable Content Types + + By default, `AFJSONRequestOperation` accepts the following MIME types, which includes the official standard, `application/json`, as well as other commonly-used types: + + - `application/json` + - `text/json` + + @warning JSON parsing will use the built-in `NSJSONSerialization` class. + */ +@interface AFJSONRequestOperation : AFHTTPRequestOperation + +///---------------------------- +/// @name Getting Response Data +///---------------------------- + +/** + A JSON object constructed from the response data. If an error occurs while parsing, `nil` will be returned, and the `error` property will be set to the error. + */ +@property (readonly, nonatomic, strong) id responseJSON; + +/** + Options for reading the response JSON data and creating the Foundation objects. For possible values, see the `NSJSONSerialization` documentation section "NSJSONReadingOptions". + */ +@property (nonatomic, assign) NSJSONReadingOptions JSONReadingOptions; + +///---------------------------------- +/// @name Creating Request Operations +///---------------------------------- + +/** + Creates and returns an `AFJSONRequestOperation` object and sets the specified success and failure callbacks. + + @param urlRequest The request object to be loaded asynchronously during execution of the operation + @param success A block object to be executed when the operation finishes successfully. This block has no return value and takes three arguments: the request sent from the client, the response received from the server, and the JSON object created from the response data of request. + @param failure A block object to be executed when the operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data as JSON. This block has no return value and takes three arguments: the request sent from the client, the response received from the server, and the error describing the network or parsing error that occurred. + + @return A new JSON request operation + */ ++ (instancetype)JSONRequestOperationWithRequest:(NSURLRequest *)urlRequest + success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, id JSON))success + failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON))failure; + +@end diff --git a/Pods/AFNetworking/AFNetworking/AFJSONRequestOperation.m b/Pods/AFNetworking/AFNetworking/AFJSONRequestOperation.m new file mode 100644 index 0000000..fffc60c --- /dev/null +++ b/Pods/AFNetworking/AFNetworking/AFJSONRequestOperation.m @@ -0,0 +1,150 @@ +// AFJSONRequestOperation.m +// +// Copyright (c) 2011 Gowalla (http://gowalla.com/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "AFJSONRequestOperation.h" + +static dispatch_queue_t json_request_operation_processing_queue() { + static dispatch_queue_t af_json_request_operation_processing_queue; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + af_json_request_operation_processing_queue = dispatch_queue_create("com.alamofire.networking.json-request.processing", DISPATCH_QUEUE_CONCURRENT); + }); + + return af_json_request_operation_processing_queue; +} + +@interface AFJSONRequestOperation () +@property (readwrite, nonatomic, strong) id responseJSON; +@property (readwrite, nonatomic, strong) NSError *JSONError; +@property (readwrite, nonatomic, strong) NSRecursiveLock *lock; +@end + +@implementation AFJSONRequestOperation +@synthesize responseJSON = _responseJSON; +@synthesize JSONReadingOptions = _JSONReadingOptions; +@synthesize JSONError = _JSONError; +@dynamic lock; + ++ (instancetype)JSONRequestOperationWithRequest:(NSURLRequest *)urlRequest + success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, id JSON))success + failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON))failure +{ + AFJSONRequestOperation *requestOperation = [(AFJSONRequestOperation *)[self alloc] initWithRequest:urlRequest]; + [requestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) { + if (success) { + success(operation.request, operation.response, responseObject); + } + } failure:^(AFHTTPRequestOperation *operation, NSError *error) { + if (failure) { + failure(operation.request, operation.response, error, [(AFJSONRequestOperation *)operation responseJSON]); + } + }]; + + return requestOperation; +} + + +- (id)responseJSON { + [self.lock lock]; + if (!_responseJSON && [self.responseData length] > 0 && [self isFinished] && !self.JSONError) { + NSError *error = nil; + + // Workaround for behavior of Rails to return a single space for `head :ok` (a workaround for a bug in Safari), which is not interpreted as valid input by NSJSONSerialization. + // See https://github.com/rails/rails/issues/1742 + if (self.responseString && ![self.responseString isEqualToString:@" "]) { + // Workaround for a bug in NSJSONSerialization when Unicode character escape codes are used instead of the actual character + // See http://stackoverflow.com/a/12843465/157142 + NSData *data = [self.responseString dataUsingEncoding:NSUTF8StringEncoding]; + + if (data) { + self.responseJSON = [NSJSONSerialization JSONObjectWithData:data options:self.JSONReadingOptions error:&error]; + } else { + NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; + [userInfo setValue:@"Operation responseData failed decoding as a UTF-8 string" forKey:NSLocalizedDescriptionKey]; + [userInfo setValue:[NSString stringWithFormat:@"Could not decode string: %@", self.responseString] forKey:NSLocalizedFailureReasonErrorKey]; + error = [[NSError alloc] initWithDomain:AFNetworkingErrorDomain code:NSURLErrorCannotDecodeContentData userInfo:userInfo]; + } + } + + self.JSONError = error; + } + [self.lock unlock]; + + return _responseJSON; +} + +- (NSError *)error { + if (_JSONError) { + return _JSONError; + } else { + return [super error]; + } +} + +#pragma mark - AFHTTPRequestOperation + ++ (NSSet *)acceptableContentTypes { + return [NSSet setWithObjects:@"application/json", @"text/json", @"text/javascript", nil]; +} + ++ (BOOL)canProcessRequest:(NSURLRequest *)request { + return [[[request URL] pathExtension] isEqualToString:@"json"] || [super canProcessRequest:request]; +} + +- (void)setCompletionBlockWithSuccess:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success + failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure +{ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warc-retain-cycles" +#pragma clang diagnostic ignored "-Wgnu" + + self.completionBlock = ^ { + if (self.error) { + if (failure) { + dispatch_async(self.failureCallbackQueue ?: dispatch_get_main_queue(), ^{ + failure(self, self.error); + }); + } + } else { + dispatch_async(json_request_operation_processing_queue(), ^{ + id JSON = self.responseJSON; + + if (self.error) { + if (failure) { + dispatch_async(self.failureCallbackQueue ?: dispatch_get_main_queue(), ^{ + failure(self, self.error); + }); + } + } else { + if (success) { + dispatch_async(self.successCallbackQueue ?: dispatch_get_main_queue(), ^{ + success(self, JSON); + }); + } + } + }); + } + }; +#pragma clang diagnostic pop +} + +@end diff --git a/Pods/AFNetworking/AFNetworking/AFNetworkActivityIndicatorManager.h b/Pods/AFNetworking/AFNetworking/AFNetworkActivityIndicatorManager.h new file mode 100644 index 0000000..714193b --- /dev/null +++ b/Pods/AFNetworking/AFNetworking/AFNetworkActivityIndicatorManager.h @@ -0,0 +1,75 @@ +// AFNetworkActivityIndicatorManager.h +// +// Copyright (c) 2011 Gowalla (http://gowalla.com/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import + +#import + +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) +#import + +/** + `AFNetworkActivityIndicatorManager` manages the state of the network activity indicator in the status bar. When enabled, it will listen for notifications indicating that a network request operation has started or finished, and start or stop animating the indicator accordingly. The number of active requests is incremented and decremented much like a stack or a semaphore, and the activity indicator will animate so long as that number is greater than zero. + + You should enable the shared instance of `AFNetworkActivityIndicatorManager` when your application finishes launching. In `AppDelegate application:didFinishLaunchingWithOptions:` you can do so with the following code: + + [[AFNetworkActivityIndicatorManager sharedManager] setEnabled:YES]; + + By setting `isNetworkActivityIndicatorVisible` to `YES` for `sharedManager`, the network activity indicator will show and hide automatically as requests start and finish. You should not ever need to call `incrementActivityCount` or `decrementActivityCount` yourself. + + See the Apple Human Interface Guidelines section about the Network Activity Indicator for more information: + http://developer.apple.com/library/iOS/#documentation/UserExperience/Conceptual/MobileHIG/UIElementGuidelines/UIElementGuidelines.html#//apple_ref/doc/uid/TP40006556-CH13-SW44 + */ +@interface AFNetworkActivityIndicatorManager : NSObject + +/** + A Boolean value indicating whether the manager is enabled. + + If YES, the manager will change status bar network activity indicator according to network operation notifications it receives. The default value is NO. + */ +@property (nonatomic, assign, getter = isEnabled) BOOL enabled; + +/** + A Boolean value indicating whether the network activity indicator is currently displayed in the status bar. + */ +@property (readonly, nonatomic, assign) BOOL isNetworkActivityIndicatorVisible; + +/** + Returns the shared network activity indicator manager object for the system. + + @return The systemwide network activity indicator manager. + */ ++ (instancetype)sharedManager; + +/** + Increments the number of active network requests. If this number was zero before incrementing, this will start animating the status bar network activity indicator. + */ +- (void)incrementActivityCount; + +/** + Decrements the number of active network requests. If this number becomes zero before decrementing, this will stop animating the status bar network activity indicator. + */ +- (void)decrementActivityCount; + +@end + +#endif diff --git a/Pods/AFNetworking/AFNetworking/AFNetworkActivityIndicatorManager.m b/Pods/AFNetworking/AFNetworking/AFNetworkActivityIndicatorManager.m new file mode 100644 index 0000000..68cbd33 --- /dev/null +++ b/Pods/AFNetworking/AFNetworking/AFNetworkActivityIndicatorManager.m @@ -0,0 +1,157 @@ +// AFNetworkActivityIndicatorManager.m +// +// Copyright (c) 2011 Gowalla (http://gowalla.com/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "AFNetworkActivityIndicatorManager.h" + +#import "AFHTTPRequestOperation.h" + +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) +static NSTimeInterval const kAFNetworkActivityIndicatorInvisibilityDelay = 0.17; + +@interface AFNetworkActivityIndicatorManager () +@property (readwrite, nonatomic, assign) NSInteger activityCount; +@property (readwrite, nonatomic, strong) NSTimer *activityIndicatorVisibilityTimer; +@property (readonly, nonatomic, getter = isNetworkActivityIndicatorVisible) BOOL networkActivityIndicatorVisible; + +- (void)updateNetworkActivityIndicatorVisibility; +- (void)updateNetworkActivityIndicatorVisibilityDelayed; +@end + +@implementation AFNetworkActivityIndicatorManager +@synthesize activityCount = _activityCount; +@synthesize activityIndicatorVisibilityTimer = _activityIndicatorVisibilityTimer; +@synthesize enabled = _enabled; +@dynamic networkActivityIndicatorVisible; + ++ (instancetype)sharedManager { + static AFNetworkActivityIndicatorManager *_sharedManager = nil; + static dispatch_once_t oncePredicate; + dispatch_once(&oncePredicate, ^{ + _sharedManager = [[self alloc] init]; + }); + + return _sharedManager; +} + ++ (NSSet *)keyPathsForValuesAffectingIsNetworkActivityIndicatorVisible { + return [NSSet setWithObject:@"activityCount"]; +} + +- (id)init { + self = [super init]; + if (!self) { + return nil; + } + + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(networkingOperationDidStart:) name:AFNetworkingOperationDidStartNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(networkingOperationDidFinish:) name:AFNetworkingOperationDidFinishNotification object:nil]; + + return self; +} + +- (void)dealloc { + [[NSNotificationCenter defaultCenter] removeObserver:self]; + + [_activityIndicatorVisibilityTimer invalidate]; + +} + +- (void)updateNetworkActivityIndicatorVisibilityDelayed { + if (self.enabled) { + // Delay hiding of activity indicator for a short interval, to avoid flickering + if (![self isNetworkActivityIndicatorVisible]) { + [self.activityIndicatorVisibilityTimer invalidate]; + self.activityIndicatorVisibilityTimer = [NSTimer timerWithTimeInterval:kAFNetworkActivityIndicatorInvisibilityDelay target:self selector:@selector(updateNetworkActivityIndicatorVisibility) userInfo:nil repeats:NO]; + [[NSRunLoop mainRunLoop] addTimer:self.activityIndicatorVisibilityTimer forMode:NSRunLoopCommonModes]; + } else { + [self performSelectorOnMainThread:@selector(updateNetworkActivityIndicatorVisibility) withObject:nil waitUntilDone:NO modes:[NSArray arrayWithObject:NSRunLoopCommonModes]]; + } + } +} + +- (BOOL)isNetworkActivityIndicatorVisible { + return _activityCount > 0; +} + +- (void)updateNetworkActivityIndicatorVisibility { + [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:[self isNetworkActivityIndicatorVisible]]; +} + +// Not exposed, but used if activityCount is set via KVC. +- (NSInteger)activityCount { + return _activityCount; +} + +- (void)setActivityCount:(NSInteger)activityCount { + @synchronized(self) { + _activityCount = activityCount; + } + + dispatch_async(dispatch_get_main_queue(), ^{ + [self updateNetworkActivityIndicatorVisibilityDelayed]; + }); +} + +- (void)incrementActivityCount { + [self willChangeValueForKey:@"activityCount"]; + @synchronized(self) { + _activityCount++; + } + [self didChangeValueForKey:@"activityCount"]; + + dispatch_async(dispatch_get_main_queue(), ^{ + [self updateNetworkActivityIndicatorVisibilityDelayed]; + }); +} + +- (void)decrementActivityCount { + [self willChangeValueForKey:@"activityCount"]; + @synchronized(self) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wgnu" + _activityCount = MAX(_activityCount - 1, 0); +#pragma clang diagnostic pop + } + [self didChangeValueForKey:@"activityCount"]; + + dispatch_async(dispatch_get_main_queue(), ^{ + [self updateNetworkActivityIndicatorVisibilityDelayed]; + }); +} + +- (void)networkingOperationDidStart:(NSNotification *)notification { + AFURLConnectionOperation *connectionOperation = [notification object]; + if (connectionOperation.request.URL) { + [self incrementActivityCount]; + } +} + +- (void)networkingOperationDidFinish:(NSNotification *)notification { + AFURLConnectionOperation *connectionOperation = [notification object]; + if (connectionOperation.request.URL) { + [self decrementActivityCount]; + } +} + +@end + +#endif diff --git a/Pods/AFNetworking/AFNetworking/AFNetworking.h b/Pods/AFNetworking/AFNetworking/AFNetworking.h new file mode 100644 index 0000000..b8f840b --- /dev/null +++ b/Pods/AFNetworking/AFNetworking/AFNetworking.h @@ -0,0 +1,43 @@ +// AFNetworking.h +// +// Copyright (c) 2011 Gowalla (http://gowalla.com/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import + +#ifndef _AFNETWORKING_ + #define _AFNETWORKING_ + + #import "AFURLConnectionOperation.h" + + #import "AFHTTPRequestOperation.h" + #import "AFJSONRequestOperation.h" + #import "AFXMLRequestOperation.h" + #import "AFPropertyListRequestOperation.h" + #import "AFHTTPClient.h" + + #import "AFImageRequestOperation.h" + + #if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) + #import "AFNetworkActivityIndicatorManager.h" + #import "UIImageView+AFNetworking.h" + #endif +#endif /* _AFNETWORKING_ */ diff --git a/Pods/AFNetworking/AFNetworking/AFPropertyListRequestOperation.h b/Pods/AFNetworking/AFNetworking/AFPropertyListRequestOperation.h new file mode 100644 index 0000000..9ebb605 --- /dev/null +++ b/Pods/AFNetworking/AFNetworking/AFPropertyListRequestOperation.h @@ -0,0 +1,68 @@ +// AFPropertyListRequestOperation.h +// +// Copyright (c) 2011 Gowalla (http://gowalla.com/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "AFHTTPRequestOperation.h" + +/** + `AFPropertyListRequestOperation` is a subclass of `AFHTTPRequestOperation` for downloading and deserializing objects with property list (plist) response data. + + ## Acceptable Content Types + + By default, `AFPropertyListRequestOperation` accepts the following MIME types: + + - `application/x-plist` + */ +@interface AFPropertyListRequestOperation : AFHTTPRequestOperation + +///---------------------------- +/// @name Getting Response Data +///---------------------------- + +/** + An object deserialized from a plist constructed using the response data. + */ +@property (readonly, nonatomic) id responsePropertyList; + +///-------------------------------------- +/// @name Managing Property List Behavior +///-------------------------------------- + +/** + One of the `NSPropertyListMutabilityOptions` options, specifying the mutability of objects deserialized from the property list. By default, this is `NSPropertyListImmutable`. + */ +@property (nonatomic, assign) NSPropertyListReadOptions propertyListReadOptions; + +/** + Creates and returns an `AFPropertyListRequestOperation` object and sets the specified success and failure callbacks. + + @param urlRequest The request object to be loaded asynchronously during execution of the operation + @param success A block object to be executed when the operation finishes successfully. This block has no return value and takes three arguments: the request sent from the client, the response received from the server, and the object deserialized from a plist constructed using the response data. + @param failure A block object to be executed when the operation finishes unsuccessfully, or that finishes successfully, but encountered an error while deserializing the object from a property list. This block has no return value and takes three arguments: the request sent from the client, the response received from the server, and the error describing the network or parsing error that occurred. + + @return A new property list request operation + */ ++ (instancetype)propertyListRequestOperationWithRequest:(NSURLRequest *)urlRequest + success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, id propertyList))success + failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id propertyList))failure; + +@end diff --git a/Pods/AFNetworking/AFNetworking/AFPropertyListRequestOperation.m b/Pods/AFNetworking/AFNetworking/AFPropertyListRequestOperation.m new file mode 100644 index 0000000..370e12b --- /dev/null +++ b/Pods/AFNetworking/AFNetworking/AFPropertyListRequestOperation.m @@ -0,0 +1,143 @@ +// AFPropertyListRequestOperation.m +// +// Copyright (c) 2011 Gowalla (http://gowalla.com/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "AFPropertyListRequestOperation.h" + +static dispatch_queue_t property_list_request_operation_processing_queue() { + static dispatch_queue_t af_property_list_request_operation_processing_queue; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + af_property_list_request_operation_processing_queue = dispatch_queue_create("com.alamofire.networking.property-list-request.processing", DISPATCH_QUEUE_CONCURRENT); + }); + + return af_property_list_request_operation_processing_queue; +} + +@interface AFPropertyListRequestOperation () +@property (readwrite, nonatomic) id responsePropertyList; +@property (readwrite, nonatomic, assign) NSPropertyListFormat propertyListFormat; +@property (readwrite, nonatomic) NSError *propertyListError; +@end + +@implementation AFPropertyListRequestOperation +@synthesize responsePropertyList = _responsePropertyList; +@synthesize propertyListReadOptions = _propertyListReadOptions; +@synthesize propertyListFormat = _propertyListFormat; +@synthesize propertyListError = _propertyListError; + ++ (instancetype)propertyListRequestOperationWithRequest:(NSURLRequest *)request + success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, id propertyList))success + failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id propertyList))failure +{ + AFPropertyListRequestOperation *requestOperation = [(AFPropertyListRequestOperation *)[self alloc] initWithRequest:request]; + [requestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) { + if (success) { + success(operation.request, operation.response, responseObject); + } + } failure:^(AFHTTPRequestOperation *operation, NSError *error) { + if (failure) { + failure(operation.request, operation.response, error, [(AFPropertyListRequestOperation *)operation responsePropertyList]); + } + }]; + + return requestOperation; +} + +- (id)initWithRequest:(NSURLRequest *)urlRequest { + self = [super initWithRequest:urlRequest]; + if (!self) { + return nil; + } + + self.propertyListReadOptions = NSPropertyListImmutable; + + return self; +} + + +- (id)responsePropertyList { + if (!_responsePropertyList && [self.responseData length] > 0 && [self isFinished]) { + NSPropertyListFormat format; + NSError *error = nil; + self.responsePropertyList = [NSPropertyListSerialization propertyListWithData:self.responseData options:self.propertyListReadOptions format:&format error:&error]; + self.propertyListFormat = format; + self.propertyListError = error; + } + + return _responsePropertyList; +} + +- (NSError *)error { + if (_propertyListError) { + return _propertyListError; + } else { + return [super error]; + } +} + +#pragma mark - AFHTTPRequestOperation + ++ (NSSet *)acceptableContentTypes { + return [NSSet setWithObjects:@"application/x-plist", nil]; +} + ++ (BOOL)canProcessRequest:(NSURLRequest *)request { + return [[[request URL] pathExtension] isEqualToString:@"plist"] || [super canProcessRequest:request]; +} + +- (void)setCompletionBlockWithSuccess:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success + failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure +{ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warc-retain-cycles" +#pragma clang diagnostic ignored "-Wgnu" + self.completionBlock = ^ { + if (self.error) { + if (failure) { + dispatch_async(self.failureCallbackQueue ?: dispatch_get_main_queue(), ^{ + failure(self, self.error); + }); + } + } else { + dispatch_async(property_list_request_operation_processing_queue(), ^(void) { + id propertyList = self.responsePropertyList; + + if (self.propertyListError) { + if (failure) { + dispatch_async(self.failureCallbackQueue ?: dispatch_get_main_queue(), ^{ + failure(self, self.error); + }); + } + } else { + if (success) { + dispatch_async(self.successCallbackQueue ?: dispatch_get_main_queue(), ^{ + success(self, propertyList); + }); + } + } + }); + } + }; +#pragma clang diagnostic pop +} + +@end diff --git a/Pods/AFNetworking/AFNetworking/AFURLConnectionOperation.h b/Pods/AFNetworking/AFNetworking/AFURLConnectionOperation.h new file mode 100644 index 0000000..0ac9e10 --- /dev/null +++ b/Pods/AFNetworking/AFNetworking/AFURLConnectionOperation.h @@ -0,0 +1,370 @@ +// AFURLConnectionOperation.h +// +// Copyright (c) 2011 Gowalla (http://gowalla.com/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import + +#import + +/** + `AFURLConnectionOperation` is a subclass of `NSOperation` that implements `NSURLConnection` delegate methods. + + ## Subclassing Notes + + This is the base class of all network request operations. You may wish to create your own subclass in order to implement additional `NSURLConnection` delegate methods (see "`NSURLConnection` Delegate Methods" below), or to provide additional properties and/or class constructors. + + If you are creating a subclass that communicates over the HTTP or HTTPS protocols, you may want to consider subclassing `AFHTTPRequestOperation` instead, as it supports specifying acceptable content types or status codes. + + ## NSURLConnection Delegate Methods + + `AFURLConnectionOperation` implements the following `NSURLConnection` delegate methods: + + - `connection:didReceiveResponse:` + - `connection:didReceiveData:` + - `connectionDidFinishLoading:` + - `connection:didFailWithError:` + - `connection:didSendBodyData:totalBytesWritten:totalBytesExpectedToWrite:` + - `connection:willCacheResponse:` + - `connectionShouldUseCredentialStorage:` + - `connection:willSendRequestForAuthenticationChallenge:` + + If any of these methods are overridden in a subclass, they _must_ call the `super` implementation first. + + ## Class Constructors + + Class constructors, or methods that return an unowned instance, are the preferred way for subclasses to encapsulate any particular logic for handling the setup or parsing of response data. For instance, `AFJSONRequestOperation` provides `JSONRequestOperationWithRequest:success:failure:`, which takes block arguments, whose parameter on for a successful request is the JSON object initialized from the `response data`. + + ## Callbacks and Completion Blocks + + The built-in `completionBlock` provided by `NSOperation` allows for custom behavior to be executed after the request finishes. It is a common pattern for class constructors in subclasses to take callback block parameters, and execute them conditionally in the body of its `completionBlock`. Make sure to handle cancelled operations appropriately when setting a `completionBlock` (i.e. returning early before parsing response data). See the implementation of any of the `AFHTTPRequestOperation` subclasses for an example of this. + + Subclasses are strongly discouraged from overriding `setCompletionBlock:`, as `AFURLConnectionOperation`'s implementation includes a workaround to mitigate retain cycles, and what Apple rather ominously refers to as ["The Deallocation Problem"](http://developer.apple.com/library/ios/#technotes/tn2109/). + + ## SSL Pinning + + Relying on the CA trust model to validate SSL certificates exposes your app to security vulnerabilities, such as man-in-the-middle attacks. For applications that connect to known servers, SSL certificate pinning provides an increased level of security, by checking server certificate validity against those specified in the app bundle. + + SSL with certificate pinning is strongly recommended for any application that transmits sensitive information to an external webservice. + + When `defaultSSLPinningMode` is defined on `AFHTTPClient` and the Security framework is linked, connections will be validated on all matching certificates with a `.cer` extension in the bundle root. + + ## NSCoding & NSCopying Conformance + + `AFURLConnectionOperation` conforms to the `NSCoding` and `NSCopying` protocols, allowing operations to be archived to disk, and copied in memory, respectively. However, because of the intrinsic limitations of capturing the exact state of an operation at a particular moment, there are some important caveats to keep in mind: + + ### NSCoding Caveats + + - Encoded operations do not include any block or stream properties. Be sure to set `completionBlock`, `outputStream`, and any callback blocks as necessary when using `-initWithCoder:` or `NSKeyedUnarchiver`. + - Operations are paused on `encodeWithCoder:`. If the operation was encoded while paused or still executing, its archived state will return `YES` for `isReady`. Otherwise, the state of an operation when encoding will remain unchanged. + + ### NSCopying Caveats + + - `-copy` and `-copyWithZone:` return a new operation with the `NSURLRequest` of the original. So rather than an exact copy of the operation at that particular instant, the copying mechanism returns a completely new instance, which can be useful for retrying operations. + - A copy of an operation will not include the `outputStream` of the original. + - Operation copies do not include `completionBlock`. `completionBlock` often strongly captures a reference to `self`, which would otherwise have the unintuitive side-effect of pointing to the _original_ operation when copied. + */ + +typedef enum { + AFSSLPinningModeNone, + AFSSLPinningModePublicKey, + AFSSLPinningModeCertificate, +} AFURLConnectionOperationSSLPinningMode; + +@interface AFURLConnectionOperation : NSOperation = 50000) || \ + (defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080) +NSURLConnectionDataDelegate, +#endif +NSCoding, NSCopying> + +///------------------------------- +/// @name Accessing Run Loop Modes +///------------------------------- + +/** + The run loop modes in which the operation will run on the network thread. By default, this is a single-member set containing `NSRunLoopCommonModes`. + */ +@property (nonatomic, strong) NSSet *runLoopModes; + +///----------------------------------------- +/// @name Getting URL Connection Information +///----------------------------------------- + +/** + The request used by the operation's connection. + */ +@property (readonly, nonatomic, strong) NSURLRequest *request; + +/** + The last response received by the operation's connection. + */ +@property (readonly, nonatomic, strong) NSURLResponse *response; + +/** + The error, if any, that occurred in the lifecycle of the request. + */ +@property (readonly, nonatomic, strong) NSError *error; + +/** + Whether the connection should accept an invalid SSL certificate. + + If `_AFNETWORKING_ALLOW_INVALID_SSL_CERTIFICATES_` is set, this property defaults to `YES` for backwards compatibility. Otherwise, this property defaults to `NO`. + */ +@property (nonatomic, assign) BOOL allowsInvalidSSLCertificate; + +///---------------------------- +/// @name Getting Response Data +///---------------------------- + +/** + The data received during the request. + */ +@property (readonly, nonatomic, strong) NSData *responseData; + +/** + The string representation of the response data. + */ +@property (readonly, nonatomic, copy) NSString *responseString; + +/** + The string encoding of the response. + + If the response does not specify a valid string encoding, `responseStringEncoding` will return `NSUTF8StringEncoding`. + */ +@property (readonly, nonatomic, assign) NSStringEncoding responseStringEncoding; + +///------------------------------- +/// @name Managing URL Credentials +///------------------------------- + +/** + Whether the URL connection should consult the credential storage for authenticating the connection. `YES` by default. + + This is the value that is returned in the `NSURLConnectionDelegate` method `-connectionShouldUseCredentialStorage:`. + */ +@property (nonatomic, assign) BOOL shouldUseCredentialStorage; + +/** + The credential used for authentication challenges in `-connection:didReceiveAuthenticationChallenge:`. + + This will be overridden by any shared credentials that exist for the username or password of the request URL, if present. + */ +@property (nonatomic, strong) NSURLCredential *credential; + +/** + The pinning mode which will be used for SSL connections. `AFSSLPinningModePublicKey` by default. + + SSL Pinning requires that the Security framework is linked with the binary. See the "SSL Pinning" section in the `AFURLConnectionOperation`" header for more information. + */ +@property (nonatomic, assign) AFURLConnectionOperationSSLPinningMode SSLPinningMode; + +///------------------------ +/// @name Accessing Streams +///------------------------ + +/** + The input stream used to read data to be sent during the request. + + This property acts as a proxy to the `HTTPBodyStream` property of `request`. + */ +@property (nonatomic, strong) NSInputStream *inputStream; + +/** + The output stream that is used to write data received until the request is finished. + + By default, data is accumulated into a buffer that is stored into `responseData` upon completion of the request. When `outputStream` is set, the data will not be accumulated into an internal buffer, and as a result, the `responseData` property of the completed request will be `nil`. The output stream will be scheduled in the network thread runloop upon being set. + */ +@property (nonatomic, strong) NSOutputStream *outputStream; + +///--------------------------------------------- +/// @name Managing Request Operation Information +///--------------------------------------------- + +/** + The user info dictionary for the receiver. + */ +@property (nonatomic, strong) NSDictionary *userInfo; + +///------------------------------------------------------ +/// @name Initializing an AFURLConnectionOperation Object +///------------------------------------------------------ + +/** + Initializes and returns a newly allocated operation object with a url connection configured with the specified url request. + + This is the designated initializer. + + @param urlRequest The request object to be used by the operation connection. + */ +- (id)initWithRequest:(NSURLRequest *)urlRequest; + +///---------------------------------- +/// @name Pausing / Resuming Requests +///---------------------------------- + +/** + Pauses the execution of the request operation. + + A paused operation returns `NO` for `-isReady`, `-isExecuting`, and `-isFinished`. As such, it will remain in an `NSOperationQueue` until it is either cancelled or resumed. Pausing a finished, cancelled, or paused operation has no effect. + */ +- (void)pause; + +/** + Whether the request operation is currently paused. + + @return `YES` if the operation is currently paused, otherwise `NO`. + */ +- (BOOL)isPaused; + +/** + Resumes the execution of the paused request operation. + + Pause/Resume behavior varies depending on the underlying implementation for the operation class. In its base implementation, resuming a paused requests restarts the original request. However, since HTTP defines a specification for how to request a specific content range, `AFHTTPRequestOperation` will resume downloading the request from where it left off, instead of restarting the original request. + */ +- (void)resume; + +///---------------------------------------------- +/// @name Configuring Backgrounding Task Behavior +///---------------------------------------------- + +/** + Specifies that the operation should continue execution after the app has entered the background, and the expiration handler for that background task. + + @param handler A handler to be called shortly before the application’s remaining background time reaches 0. The handler is wrapped in a block that cancels the operation, and cleans up and marks the end of execution, unlike the `handler` parameter in `UIApplication -beginBackgroundTaskWithExpirationHandler:`, which expects this to be done in the handler itself. The handler is called synchronously on the main thread, thus blocking the application’s suspension momentarily while the application is notified. + */ +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) +- (void)setShouldExecuteAsBackgroundTaskWithExpirationHandler:(void (^)(void))handler; +#endif + +///--------------------------------- +/// @name Setting Progress Callbacks +///--------------------------------- + +/** + Sets a callback to be called when an undetermined number of bytes have been uploaded to the server. + + @param block A block object to be called when an undetermined number of bytes have been uploaded to the server. This block has no return value and takes three arguments: the number of bytes written since the last time the upload progress block was called, the total bytes written, and the total bytes expected to be written during the request, as initially determined by the length of the HTTP body. This block may be called multiple times, and will execute on the main thread. + */ +- (void)setUploadProgressBlock:(void (^)(NSUInteger bytesWritten, long long totalBytesWritten, long long totalBytesExpectedToWrite))block; + +/** + Sets a callback to be called when an undetermined number of bytes have been downloaded from the server. + + @param block A block object to be called when an undetermined number of bytes have been downloaded from the server. This block has no return value and takes three arguments: the number of bytes read since the last time the download progress block was called, the total bytes read, and the total bytes expected to be read during the request, as initially determined by the expected content size of the `NSHTTPURLResponse` object. This block may be called multiple times, and will execute on the main thread. + */ +- (void)setDownloadProgressBlock:(void (^)(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead))block; + +///------------------------------------------------- +/// @name Setting NSURLConnection Delegate Callbacks +///------------------------------------------------- + +/** + Sets a block to be executed when the connection will authenticate a challenge in order to download its request, as handled by the `NSURLConnectionDelegate` method `connection:willSendRequestForAuthenticationChallenge:`. + + @param block A block object to be executed when the connection will authenticate a challenge in order to download its request. The block has no return type and takes two arguments: the URL connection object, and the challenge that must be authenticated. This block must invoke one of the challenge-responder methods (NSURLAuthenticationChallengeSender protocol). + + If `allowsInvalidSSLCertificate` is set to YES, `connection:willSendRequestForAuthenticationChallenge:` will attempt to have the challenge sender use credentials with invalid SSL certificates. + */ +- (void)setWillSendRequestForAuthenticationChallengeBlock:(void (^)(NSURLConnection *connection, NSURLAuthenticationChallenge *challenge))block; + +/** + Sets a block to be executed when the server redirects the request from one URL to another URL, or when the request URL changed by the `NSURLProtocol` subclass handling the request in order to standardize its format, as handled by the `NSURLConnectionDelegate` method `connection:willSendRequest:redirectResponse:`. + + @param block A block object to be executed when the request URL was changed. The block returns an `NSURLRequest` object, the URL request to redirect, and takes three arguments: the URL connection object, the the proposed redirected request, and the URL response that caused the redirect. + */ +- (void)setRedirectResponseBlock:(NSURLRequest * (^)(NSURLConnection *connection, NSURLRequest *request, NSURLResponse *redirectResponse))block; + +/** + Sets a block to be executed to modify the response a connection will cache, if any, as handled by the `NSURLConnectionDelegate` method `connection:willCacheResponse:`. + + @param block A block object to be executed to determine what response a connection will cache, if any. The block returns an `NSCachedURLResponse` object, the cached response to store in memory or `nil` to prevent the response from being cached, and takes two arguments: the URL connection object, and the cached response provided for the request. + */ +- (void)setCacheResponseBlock:(NSCachedURLResponse * (^)(NSURLConnection *connection, NSCachedURLResponse *cachedResponse))block; + +@end + +///---------------- +/// @name Constants +///---------------- + +/** + ## SSL Pinning Options + + The following constants are provided by `AFURLConnectionOperation` as possible SSL Pinning options. + + enum { + AFSSLPinningModeNone, + AFSSLPinningModePublicKey, + AFSSLPinningModeCertificate, + } + + `AFSSLPinningModeNone` + Do not pin SSL connections + + `AFSSLPinningModePublicKey` + Pin SSL connections to certificate public key (SPKI). + + `AFSSLPinningModeCertificate` + Pin SSL connections to exact certificate. This may cause problems when your certificate expires and needs re-issuance. + + ## User info dictionary keys + + These keys may exist in the user info dictionary, in addition to those defined for NSError. + + - `NSString * const AFNetworkingOperationFailingURLRequestErrorKey` + - `NSString * const AFNetworkingOperationFailingURLResponseErrorKey` + + ### Constants + + `AFNetworkingOperationFailingURLRequestErrorKey` + The corresponding value is an `NSURLRequest` containing the request of the operation associated with an error. This key is only present in the `AFNetworkingErrorDomain`. + + `AFNetworkingOperationFailingURLResponseErrorKey` + The corresponding value is an `NSURLResponse` containing the response of the operation associated with an error. This key is only present in the `AFNetworkingErrorDomain`. + + ## Error Domains + + The following error domain is predefined. + + - `NSString * const AFNetworkingErrorDomain` + + ### Constants + + `AFNetworkingErrorDomain` + AFNetworking errors. Error codes for `AFNetworkingErrorDomain` correspond to codes in `NSURLErrorDomain`. + */ +extern NSString * const AFNetworkingErrorDomain; +extern NSString * const AFNetworkingOperationFailingURLRequestErrorKey; +extern NSString * const AFNetworkingOperationFailingURLResponseErrorKey; + +///-------------------- +/// @name Notifications +///-------------------- + +/** + Posted when an operation begins executing. + */ +extern NSString * const AFNetworkingOperationDidStartNotification; + +/** + Posted when an operation finishes. + */ +extern NSString * const AFNetworkingOperationDidFinishNotification; diff --git a/Pods/AFNetworking/AFNetworking/AFURLConnectionOperation.m b/Pods/AFNetworking/AFNetworking/AFURLConnectionOperation.m new file mode 100644 index 0000000..5885369 --- /dev/null +++ b/Pods/AFNetworking/AFNetworking/AFURLConnectionOperation.m @@ -0,0 +1,862 @@ +// AFURLConnectionOperation.m +// +// Copyright (c) 2011 Gowalla (http://gowalla.com/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "AFURLConnectionOperation.h" + +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) +#import +#endif + +#if !__has_feature(objc_arc) +#error AFNetworking must be built with ARC. +// You can turn on ARC for only AFNetworking files by adding -fobjc-arc to the build phase for each of its files. +#endif + +typedef enum { + AFOperationPausedState = -1, + AFOperationReadyState = 1, + AFOperationExecutingState = 2, + AFOperationFinishedState = 3, +} _AFOperationState; + +typedef signed short AFOperationState; + +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) +typedef UIBackgroundTaskIdentifier AFBackgroundTaskIdentifier; +#else +typedef id AFBackgroundTaskIdentifier; +#endif + +static NSString * const kAFNetworkingLockName = @"com.alamofire.networking.operation.lock"; + +NSString * const AFNetworkingErrorDomain = @"AFNetworkingErrorDomain"; +NSString * const AFNetworkingOperationFailingURLRequestErrorKey = @"AFNetworkingOperationFailingURLRequestErrorKey"; +NSString * const AFNetworkingOperationFailingURLResponseErrorKey = @"AFNetworkingOperationFailingURLResponseErrorKey"; + +NSString * const AFNetworkingOperationDidStartNotification = @"com.alamofire.networking.operation.start"; +NSString * const AFNetworkingOperationDidFinishNotification = @"com.alamofire.networking.operation.finish"; + +typedef void (^AFURLConnectionOperationProgressBlock)(NSUInteger bytes, long long totalBytes, long long totalBytesExpected); +typedef void (^AFURLConnectionOperationAuthenticationChallengeBlock)(NSURLConnection *connection, NSURLAuthenticationChallenge *challenge); +typedef NSCachedURLResponse * (^AFURLConnectionOperationCacheResponseBlock)(NSURLConnection *connection, NSCachedURLResponse *cachedResponse); +typedef NSURLRequest * (^AFURLConnectionOperationRedirectResponseBlock)(NSURLConnection *connection, NSURLRequest *request, NSURLResponse *redirectResponse); + +static inline NSString * AFKeyPathFromOperationState(AFOperationState state) { + switch (state) { + case AFOperationReadyState: + return @"isReady"; + case AFOperationExecutingState: + return @"isExecuting"; + case AFOperationFinishedState: + return @"isFinished"; + case AFOperationPausedState: + return @"isPaused"; + default: + return @"state"; + } +} + +static inline BOOL AFStateTransitionIsValid(AFOperationState fromState, AFOperationState toState, BOOL isCancelled) { + switch (fromState) { + case AFOperationReadyState: + switch (toState) { + case AFOperationPausedState: + case AFOperationExecutingState: + return YES; + case AFOperationFinishedState: + return isCancelled; + default: + return NO; + } + case AFOperationExecutingState: + switch (toState) { + case AFOperationPausedState: + case AFOperationFinishedState: + return YES; + default: + return NO; + } + case AFOperationFinishedState: + return NO; + case AFOperationPausedState: + return toState == AFOperationReadyState; + default: + return YES; + } +} + +#if !defined(__IPHONE_OS_VERSION_MIN_REQUIRED) +static NSData *AFSecKeyGetData(SecKeyRef key) { + CFDataRef data = NULL; + +#if defined(NS_BLOCK_ASSERTIONS) + SecItemExport(key, kSecFormatUnknown, kSecItemPemArmour, NULL, &data); +#else + OSStatus status = SecItemExport(key, kSecFormatUnknown, kSecItemPemArmour, NULL, &data); + NSCAssert(status == errSecSuccess, @"SecItemExport error: %ld", (long int)status); +#endif + + NSCParameterAssert(data); + + return (__bridge_transfer NSData *)data; +} +#endif + +static BOOL AFSecKeyIsEqualToKey(SecKeyRef key1, SecKeyRef key2) { +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) + return [(__bridge id)key1 isEqual:(__bridge id)key2]; +#else + return [AFSecKeyGetData(key1) isEqual:AFSecKeyGetData(key2)]; +#endif +} + +@interface AFURLConnectionOperation () +@property (readwrite, nonatomic, assign) AFOperationState state; +@property (readwrite, nonatomic, assign, getter = isCancelled) BOOL cancelled; +@property (readwrite, nonatomic, strong) NSRecursiveLock *lock; +@property (readwrite, nonatomic, strong) NSURLConnection *connection; +@property (readwrite, nonatomic, strong) NSURLRequest *request; +@property (readwrite, nonatomic, strong) NSURLResponse *response; +@property (readwrite, nonatomic, strong) NSError *error; +@property (readwrite, nonatomic, strong) NSData *responseData; +@property (readwrite, nonatomic, copy) NSString *responseString; +@property (readwrite, nonatomic, assign) NSStringEncoding responseStringEncoding; +@property (readwrite, nonatomic, assign) long long totalBytesRead; +@property (readwrite, nonatomic, assign) AFBackgroundTaskIdentifier backgroundTaskIdentifier; +@property (readwrite, nonatomic, copy) AFURLConnectionOperationProgressBlock uploadProgress; +@property (readwrite, nonatomic, copy) AFURLConnectionOperationProgressBlock downloadProgress; +@property (readwrite, nonatomic, copy) AFURLConnectionOperationAuthenticationChallengeBlock authenticationChallenge; +@property (readwrite, nonatomic, copy) AFURLConnectionOperationCacheResponseBlock cacheResponse; +@property (readwrite, nonatomic, copy) AFURLConnectionOperationRedirectResponseBlock redirectResponse; + +- (void)operationDidStart; +- (void)finish; +- (void)cancelConnection; +@end + +@implementation AFURLConnectionOperation +@synthesize state = _state; +@synthesize cancelled = _cancelled; +@synthesize connection = _connection; +@synthesize runLoopModes = _runLoopModes; +@synthesize request = _request; +@synthesize response = _response; +@synthesize error = _error; +@synthesize allowsInvalidSSLCertificate = _allowsInvalidSSLCertificate; +@synthesize responseData = _responseData; +@synthesize responseString = _responseString; +@synthesize responseStringEncoding = _responseStringEncoding; +@synthesize totalBytesRead = _totalBytesRead; +@dynamic inputStream; +@synthesize outputStream = _outputStream; +@synthesize credential = _credential; +@synthesize SSLPinningMode = _SSLPinningMode; +@synthesize shouldUseCredentialStorage = _shouldUseCredentialStorage; +@synthesize userInfo = _userInfo; +@synthesize backgroundTaskIdentifier = _backgroundTaskIdentifier; +@synthesize uploadProgress = _uploadProgress; +@synthesize downloadProgress = _downloadProgress; +@synthesize authenticationChallenge = _authenticationChallenge; +@synthesize cacheResponse = _cacheResponse; +@synthesize redirectResponse = _redirectResponse; +@synthesize lock = _lock; + ++ (void)networkRequestThreadEntryPoint:(id __unused)object { + @autoreleasepool { + [[NSThread currentThread] setName:@"AFNetworking"]; + + NSRunLoop *runLoop = [NSRunLoop currentRunLoop]; + [runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode]; + [runLoop run]; + } +} + ++ (NSThread *)networkRequestThread { + static NSThread *_networkRequestThread = nil; + static dispatch_once_t oncePredicate; + dispatch_once(&oncePredicate, ^{ + _networkRequestThread = [[NSThread alloc] initWithTarget:self selector:@selector(networkRequestThreadEntryPoint:) object:nil]; + [_networkRequestThread start]; + }); + + return _networkRequestThread; +} + ++ (NSArray *)pinnedCertificates { + static NSArray *_pinnedCertificates = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + NSBundle *bundle = [NSBundle mainBundle]; + NSArray *paths = [bundle pathsForResourcesOfType:@"cer" inDirectory:@"."]; + + NSMutableArray *certificates = [NSMutableArray arrayWithCapacity:[paths count]]; + for (NSString *path in paths) { + NSData *certificateData = [NSData dataWithContentsOfFile:path]; + [certificates addObject:certificateData]; + } + + _pinnedCertificates = [[NSArray alloc] initWithArray:certificates]; + }); + + return _pinnedCertificates; +} + ++ (NSArray *)pinnedPublicKeys { + static NSArray *_pinnedPublicKeys = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + NSArray *pinnedCertificates = [self pinnedCertificates]; + NSMutableArray *publicKeys = [NSMutableArray arrayWithCapacity:[pinnedCertificates count]]; + + for (NSData *data in pinnedCertificates) { + SecCertificateRef allowedCertificate = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)data); + NSParameterAssert(allowedCertificate); + + SecCertificateRef allowedCertificates[] = {allowedCertificate}; + CFArrayRef certificates = CFArrayCreate(NULL, (const void **)allowedCertificates, 1, NULL); + + SecPolicyRef policy = SecPolicyCreateBasicX509(); + SecTrustRef allowedTrust = NULL; + OSStatus status = SecTrustCreateWithCertificates(certificates, policy, &allowedTrust); + NSAssert(status == errSecSuccess, @"SecTrustCreateWithCertificates error: %ld", (long int)status); + if (status == errSecSuccess && allowedTrust) { + SecTrustResultType result = 0; + status = SecTrustEvaluate(allowedTrust, &result); + NSAssert(status == errSecSuccess, @"SecTrustEvaluate error: %ld", (long int)status); + if (status == errSecSuccess) { + SecKeyRef allowedPublicKey = SecTrustCopyPublicKey(allowedTrust); + NSParameterAssert(allowedPublicKey); + if (allowedPublicKey) { + [publicKeys addObject:(__bridge_transfer id)allowedPublicKey]; + } + } + + CFRelease(allowedTrust); + } + + CFRelease(policy); + CFRelease(certificates); + CFRelease(allowedCertificate); + } + + _pinnedPublicKeys = [[NSArray alloc] initWithArray:publicKeys]; + }); + + return _pinnedPublicKeys; +} + +- (id)initWithRequest:(NSURLRequest *)urlRequest { + NSParameterAssert(urlRequest); + + self = [super init]; + if (!self) { + return nil; + } + + self.lock = [[NSRecursiveLock alloc] init]; + self.lock.name = kAFNetworkingLockName; + + self.runLoopModes = [NSSet setWithObject:NSRunLoopCommonModes]; + + self.request = urlRequest; + + self.shouldUseCredentialStorage = YES; + + // #ifdef included for backwards-compatibility +#ifdef _AFNETWORKING_ALLOW_INVALID_SSL_CERTIFICATES_ + self.allowsInvalidSSLCertificate = YES; +#endif + + self.state = AFOperationReadyState; + + return self; +} + +- (void)dealloc { + if (_outputStream) { + [_outputStream close]; + _outputStream = nil; + } + +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) + if (_backgroundTaskIdentifier) { + [[UIApplication sharedApplication] endBackgroundTask:_backgroundTaskIdentifier]; + _backgroundTaskIdentifier = UIBackgroundTaskInvalid; + } +#endif +} + +- (NSString *)description { + return [NSString stringWithFormat:@"<%@: %p, state: %@, cancelled: %@ request: %@, response: %@>", NSStringFromClass([self class]), self, AFKeyPathFromOperationState(self.state), ([self isCancelled] ? @"YES" : @"NO"), self.request, self.response]; +} + +- (void)setCompletionBlock:(void (^)(void))block { + [self.lock lock]; + if (!block) { + [super setCompletionBlock:nil]; + } else { + __weak __typeof(&*self)weakSelf = self; + [super setCompletionBlock:^ { + __strong __typeof(&*weakSelf)strongSelf = weakSelf; + + block(); + [strongSelf setCompletionBlock:nil]; + }]; + } + [self.lock unlock]; +} + +- (NSInputStream *)inputStream { + return self.request.HTTPBodyStream; +} + +- (void)setInputStream:(NSInputStream *)inputStream { + [self willChangeValueForKey:@"inputStream"]; + NSMutableURLRequest *mutableRequest = [self.request mutableCopy]; + mutableRequest.HTTPBodyStream = inputStream; + self.request = mutableRequest; + [self didChangeValueForKey:@"inputStream"]; +} + +- (NSOutputStream *)outputStream { + if (!_outputStream) { + self.outputStream = [NSOutputStream outputStreamToMemory]; + } + + return _outputStream; +} + +- (void)setOutputStream:(NSOutputStream *)outputStream { + [self.lock lock]; + if (outputStream != _outputStream) { + [self willChangeValueForKey:@"outputStream"]; + if (_outputStream) { + [_outputStream close]; + } + _outputStream = outputStream; + [self didChangeValueForKey:@"outputStream"]; + } + [self.lock unlock]; +} + +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) +- (void)setShouldExecuteAsBackgroundTaskWithExpirationHandler:(void (^)(void))handler { + [self.lock lock]; + if (!self.backgroundTaskIdentifier) { + UIApplication *application = [UIApplication sharedApplication]; + __weak __typeof(&*self)weakSelf = self; + self.backgroundTaskIdentifier = [application beginBackgroundTaskWithExpirationHandler:^{ + __strong __typeof(&*weakSelf)strongSelf = weakSelf; + + if (handler) { + handler(); + } + + if (strongSelf) { + [strongSelf cancel]; + + [application endBackgroundTask:strongSelf.backgroundTaskIdentifier]; + strongSelf.backgroundTaskIdentifier = UIBackgroundTaskInvalid; + } + }]; + } + [self.lock unlock]; +} +#endif + +- (void)setUploadProgressBlock:(void (^)(NSUInteger bytesWritten, long long totalBytesWritten, long long totalBytesExpectedToWrite))block { + self.uploadProgress = block; +} + +- (void)setDownloadProgressBlock:(void (^)(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead))block { + self.downloadProgress = block; +} + +- (void)setWillSendRequestForAuthenticationChallengeBlock:(void (^)(NSURLConnection *connection, NSURLAuthenticationChallenge *challenge))block { + self.authenticationChallenge = block; +} + +- (void)setCacheResponseBlock:(NSCachedURLResponse * (^)(NSURLConnection *connection, NSCachedURLResponse *cachedResponse))block { + self.cacheResponse = block; +} + +- (void)setRedirectResponseBlock:(NSURLRequest * (^)(NSURLConnection *connection, NSURLRequest *request, NSURLResponse *redirectResponse))block { + self.redirectResponse = block; +} + +- (void)setState:(AFOperationState)state { + if (!AFStateTransitionIsValid(self.state, state, [self isCancelled])) { + return; + } + + [self.lock lock]; + NSString *oldStateKey = AFKeyPathFromOperationState(self.state); + NSString *newStateKey = AFKeyPathFromOperationState(state); + + [self willChangeValueForKey:newStateKey]; + [self willChangeValueForKey:oldStateKey]; + _state = state; + [self didChangeValueForKey:oldStateKey]; + [self didChangeValueForKey:newStateKey]; + [self.lock unlock]; +} + +- (NSString *)responseString { + [self.lock lock]; + if (!_responseString && self.response && self.responseData) { + self.responseString = [[NSString alloc] initWithData:self.responseData encoding:self.responseStringEncoding]; + } + [self.lock unlock]; + + return _responseString; +} + +- (NSStringEncoding)responseStringEncoding { + [self.lock lock]; + if (!_responseStringEncoding && self.response) { + NSStringEncoding stringEncoding = NSUTF8StringEncoding; + if (self.response.textEncodingName) { + CFStringEncoding IANAEncoding = CFStringConvertIANACharSetNameToEncoding((__bridge CFStringRef)self.response.textEncodingName); + if (IANAEncoding != kCFStringEncodingInvalidId) { + stringEncoding = CFStringConvertEncodingToNSStringEncoding(IANAEncoding); + } + } + + self.responseStringEncoding = stringEncoding; + } + [self.lock unlock]; + + return _responseStringEncoding; +} + +- (void)pause { + if ([self isPaused] || [self isFinished] || [self isCancelled]) { + return; + } + + [self.lock lock]; + + if ([self isExecuting]) { + [self.connection performSelector:@selector(cancel) onThread:[[self class] networkRequestThread] withObject:nil waitUntilDone:NO modes:[self.runLoopModes allObjects]]; + + dispatch_async(dispatch_get_main_queue(), ^{ + NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; + [notificationCenter postNotificationName:AFNetworkingOperationDidFinishNotification object:self]; + }); + } + + self.state = AFOperationPausedState; + + [self.lock unlock]; +} + +- (BOOL)isPaused { + return self.state == AFOperationPausedState; +} + +- (void)resume { + if (![self isPaused]) { + return; + } + + [self.lock lock]; + self.state = AFOperationReadyState; + + [self start]; + [self.lock unlock]; +} + +#pragma mark - NSOperation + +- (BOOL)isReady { + return self.state == AFOperationReadyState && [super isReady]; +} + +- (BOOL)isExecuting { + return self.state == AFOperationExecutingState; +} + +- (BOOL)isFinished { + return self.state == AFOperationFinishedState; +} + +- (BOOL)isConcurrent { + return YES; +} + +- (void)start { + [self.lock lock]; + if ([self isReady]) { + self.state = AFOperationExecutingState; + + [self performSelector:@selector(operationDidStart) onThread:[[self class] networkRequestThread] withObject:nil waitUntilDone:NO modes:[self.runLoopModes allObjects]]; + } + [self.lock unlock]; +} + +- (void)operationDidStart { + [self.lock lock]; + if (![self isCancelled]) { + self.connection = [[NSURLConnection alloc] initWithRequest:self.request delegate:self startImmediately:NO]; + + NSRunLoop *runLoop = [NSRunLoop currentRunLoop]; + for (NSString *runLoopMode in self.runLoopModes) { + [self.connection scheduleInRunLoop:runLoop forMode:runLoopMode]; + [self.outputStream scheduleInRunLoop:runLoop forMode:runLoopMode]; + } + + [self.connection start]; + } + [self.lock unlock]; + + dispatch_async(dispatch_get_main_queue(), ^{ + [[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingOperationDidStartNotification object:self]; + }); + + if ([self isCancelled]) { + NSDictionary *userInfo = nil; + if ([self.request URL]) { + userInfo = [NSDictionary dictionaryWithObject:[self.request URL] forKey:NSURLErrorFailingURLErrorKey]; + } + self.error = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorCancelled userInfo:userInfo]; + + [self finish]; + } +} + +- (void)finish { + self.state = AFOperationFinishedState; + + dispatch_async(dispatch_get_main_queue(), ^{ + [[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingOperationDidFinishNotification object:self]; + }); +} + +- (void)cancel { + [self.lock lock]; + if (![self isFinished] && ![self isCancelled]) { + [self willChangeValueForKey:@"isCancelled"]; + _cancelled = YES; + [super cancel]; + [self didChangeValueForKey:@"isCancelled"]; + + // Cancel the connection on the thread it runs on to prevent race conditions + [self performSelector:@selector(cancelConnection) onThread:[[self class] networkRequestThread] withObject:nil waitUntilDone:NO modes:[self.runLoopModes allObjects]]; + } + [self.lock unlock]; +} + +- (void)cancelConnection { + NSDictionary *userInfo = nil; + if ([self.request URL]) { + userInfo = [NSDictionary dictionaryWithObject:[self.request URL] forKey:NSURLErrorFailingURLErrorKey]; + } + NSError *error = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorCancelled userInfo:userInfo]; + + if (![self isFinished] && self.connection) { + [self.connection cancel]; + [self performSelector:@selector(connection:didFailWithError:) withObject:self.connection withObject:error]; + } +} + +#pragma mark - NSURLConnectionDelegate + +- (void)connection:(NSURLConnection *)connection +willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge +{ + if (self.authenticationChallenge) { + self.authenticationChallenge(connection, challenge); + return; + } + + if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) { + SecTrustRef serverTrust = challenge.protectionSpace.serverTrust; + + SecPolicyRef policy = SecPolicyCreateBasicX509(); + SecTrustEvaluate(serverTrust, NULL); + CFIndex certificateCount = SecTrustGetCertificateCount(serverTrust); + NSMutableArray *trustChain = [NSMutableArray arrayWithCapacity:certificateCount]; + + for (CFIndex i = 0; i < certificateCount; i++) { + SecCertificateRef certificate = SecTrustGetCertificateAtIndex(serverTrust, i); + + if (self.SSLPinningMode == AFSSLPinningModeCertificate) { + [trustChain addObject:(__bridge_transfer NSData *)SecCertificateCopyData(certificate)]; + } else if (self.SSLPinningMode == AFSSLPinningModePublicKey) { + SecCertificateRef someCertificates[] = {certificate}; + CFArrayRef certificates = CFArrayCreate(NULL, (const void **)someCertificates, 1, NULL); + + SecTrustRef trust = NULL; + + OSStatus status = SecTrustCreateWithCertificates(certificates, policy, &trust); + NSAssert(status == errSecSuccess, @"SecTrustCreateWithCertificates error: %ld", (long int)status); + if (status == errSecSuccess && trust) { + SecTrustResultType result; + status = SecTrustEvaluate(trust, &result); + NSAssert(status == errSecSuccess, @"SecTrustEvaluate error: %ld", (long int)status); + if (status == errSecSuccess) { + [trustChain addObject:(__bridge_transfer id)SecTrustCopyPublicKey(trust)]; + } + + CFRelease(trust); + } + + CFRelease(certificates); + } + } + + CFRelease(policy); + + switch (self.SSLPinningMode) { + case AFSSLPinningModePublicKey: { + NSArray *pinnedPublicKeys = [self.class pinnedPublicKeys]; + NSAssert([pinnedPublicKeys count] > 0, @"AFSSLPinningModePublicKey needs at least one key file in the application bundle"); + + for (id publicKey in trustChain) { + for (id pinnedPublicKey in pinnedPublicKeys) { + if (AFSecKeyIsEqualToKey((__bridge SecKeyRef)publicKey, (__bridge SecKeyRef)pinnedPublicKey)) { + NSURLCredential *credential = [NSURLCredential credentialForTrust:serverTrust]; + [[challenge sender] useCredential:credential forAuthenticationChallenge:challenge]; + return; + } + } + } + + NSLog(@"Error: Unknown Public Key during Pinning operation"); + [[challenge sender] cancelAuthenticationChallenge:challenge]; + break; + } + case AFSSLPinningModeCertificate: { + NSAssert([[self.class pinnedCertificates] count] > 0, @"AFSSLPinningModeCertificate needs at least one certificate file in the application bundle"); + for (id serverCertificateData in trustChain) { + if ([[self.class pinnedCertificates] containsObject:serverCertificateData]) { + NSURLCredential *credential = [NSURLCredential credentialForTrust:serverTrust]; + [[challenge sender] useCredential:credential forAuthenticationChallenge:challenge]; + return; + } + } + + NSLog(@"Error: Unknown Certificate during Pinning operation"); + [[challenge sender] cancelAuthenticationChallenge:challenge]; + break; + } + case AFSSLPinningModeNone: { + if (self.allowsInvalidSSLCertificate){ + NSURLCredential *credential = [NSURLCredential credentialForTrust:serverTrust]; + [[challenge sender] useCredential:credential forAuthenticationChallenge:challenge]; + } else { + SecTrustResultType result = 0; + OSStatus status = SecTrustEvaluate(serverTrust, &result); + NSAssert(status == errSecSuccess, @"SecTrustEvaluate error: %ld", (long int)status); + + if (status == errSecSuccess && (result == kSecTrustResultUnspecified || result == kSecTrustResultProceed)) { + NSURLCredential *credential = [NSURLCredential credentialForTrust:serverTrust]; + [[challenge sender] useCredential:credential forAuthenticationChallenge:challenge]; + } else { + [[challenge sender] cancelAuthenticationChallenge:challenge]; + } + } + break; + } + } + } else { + if ([challenge previousFailureCount] == 0) { + if (self.credential) { + [[challenge sender] useCredential:self.credential forAuthenticationChallenge:challenge]; + } else { + [[challenge sender] continueWithoutCredentialForAuthenticationChallenge:challenge]; + } + } else { + [[challenge sender] continueWithoutCredentialForAuthenticationChallenge:challenge]; + } + } +} + +- (BOOL)connectionShouldUseCredentialStorage:(NSURLConnection __unused *)connection { + return self.shouldUseCredentialStorage; +} + +- (NSURLRequest *)connection:(NSURLConnection *)connection + willSendRequest:(NSURLRequest *)request + redirectResponse:(NSURLResponse *)redirectResponse +{ + if (self.redirectResponse) { + return self.redirectResponse(connection, request, redirectResponse); + } else { + return request; + } +} + +- (void)connection:(NSURLConnection __unused *)connection + didSendBodyData:(NSInteger)bytesWritten + totalBytesWritten:(NSInteger)totalBytesWritten +totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite +{ + if (self.uploadProgress) { + dispatch_async(dispatch_get_main_queue(), ^{ + self.uploadProgress((NSUInteger)bytesWritten, totalBytesWritten, totalBytesExpectedToWrite); + }); + } +} + +- (void)connection:(NSURLConnection __unused *)connection +didReceiveResponse:(NSURLResponse *)response +{ + self.response = response; + + [self.outputStream open]; +} + +- (void)connection:(NSURLConnection __unused *)connection + didReceiveData:(NSData *)data +{ + NSUInteger length = [data length]; + while (YES) { + NSUInteger totalNumberOfBytesWritten = 0; + if ([self.outputStream hasSpaceAvailable]) { + const uint8_t *dataBuffer = (uint8_t *)[data bytes]; + + NSInteger numberOfBytesWritten = 0; + while (totalNumberOfBytesWritten < length) { + numberOfBytesWritten = [self.outputStream write:&dataBuffer[0] maxLength:length]; + if (numberOfBytesWritten == -1) { + break; + } + + totalNumberOfBytesWritten += numberOfBytesWritten; + } + + break; + } + + if (self.outputStream.streamError) { + [self.connection cancel]; + [self performSelector:@selector(connection:didFailWithError:) withObject:self.connection withObject:self.outputStream.streamError]; + return; + } + } + + dispatch_async(dispatch_get_main_queue(), ^{ + self.totalBytesRead += length; + + if (self.downloadProgress) { + self.downloadProgress(length, self.totalBytesRead, self.response.expectedContentLength); + } + }); +} + +- (void)connectionDidFinishLoading:(NSURLConnection __unused *)connection { + self.responseData = [self.outputStream propertyForKey:NSStreamDataWrittenToMemoryStreamKey]; + + [self.outputStream close]; + + [self finish]; + + self.connection = nil; +} + +- (void)connection:(NSURLConnection __unused *)connection + didFailWithError:(NSError *)error +{ + self.error = error; + + [self.outputStream close]; + + [self finish]; + + self.connection = nil; +} + +- (NSCachedURLResponse *)connection:(NSURLConnection *)connection + willCacheResponse:(NSCachedURLResponse *)cachedResponse +{ + if (self.cacheResponse) { + return self.cacheResponse(connection, cachedResponse); + } else { + if ([self isCancelled]) { + return nil; + } + + return cachedResponse; + } +} + +#pragma mark - NSCoding + +- (id)initWithCoder:(NSCoder *)aDecoder { + NSURLRequest *request = [aDecoder decodeObjectForKey:@"request"]; + + self = [self initWithRequest:request]; + if (!self) { + return nil; + } + + self.state = (AFOperationState)[aDecoder decodeIntegerForKey:@"state"]; + self.cancelled = [aDecoder decodeBoolForKey:@"isCancelled"]; + self.response = [aDecoder decodeObjectForKey:@"response"]; + self.error = [aDecoder decodeObjectForKey:@"error"]; + self.responseData = [aDecoder decodeObjectForKey:@"responseData"]; + self.totalBytesRead = [[aDecoder decodeObjectForKey:@"totalBytesRead"] longLongValue]; + self.allowsInvalidSSLCertificate = [[aDecoder decodeObjectForKey:@"allowsInvalidSSLCertificate"] boolValue]; + + return self; +} + +- (void)encodeWithCoder:(NSCoder *)aCoder { + [self pause]; + + [aCoder encodeObject:self.request forKey:@"request"]; + + switch (self.state) { + case AFOperationExecutingState: + case AFOperationPausedState: + [aCoder encodeInteger:AFOperationReadyState forKey:@"state"]; + break; + default: + [aCoder encodeInteger:self.state forKey:@"state"]; + break; + } + + [aCoder encodeBool:[self isCancelled] forKey:@"isCancelled"]; + [aCoder encodeObject:self.response forKey:@"response"]; + [aCoder encodeObject:self.error forKey:@"error"]; + [aCoder encodeObject:self.responseData forKey:@"responseData"]; + [aCoder encodeObject:[NSNumber numberWithLongLong:self.totalBytesRead] forKey:@"totalBytesRead"]; + [aCoder encodeObject:[NSNumber numberWithBool:self.allowsInvalidSSLCertificate] forKey:@"allowsInvalidSSLCertificate"]; +} + +#pragma mark - NSCopying + +- (id)copyWithZone:(NSZone *)zone { + AFURLConnectionOperation *operation = [(AFURLConnectionOperation *)[[self class] allocWithZone:zone] initWithRequest:self.request]; + + operation.uploadProgress = self.uploadProgress; + operation.downloadProgress = self.downloadProgress; + operation.authenticationChallenge = self.authenticationChallenge; + operation.cacheResponse = self.cacheResponse; + operation.redirectResponse = self.redirectResponse; + operation.allowsInvalidSSLCertificate = self.allowsInvalidSSLCertificate; + + return operation; +} + +@end diff --git a/Pods/AFNetworking/AFNetworking/AFXMLRequestOperation.h b/Pods/AFNetworking/AFNetworking/AFXMLRequestOperation.h new file mode 100644 index 0000000..4130932 --- /dev/null +++ b/Pods/AFNetworking/AFNetworking/AFXMLRequestOperation.h @@ -0,0 +1,89 @@ +// AFXMLRequestOperation.h +// +// Copyright (c) 2011 Gowalla (http://gowalla.com/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "AFHTTPRequestOperation.h" + +#import + +/** + `AFXMLRequestOperation` is a subclass of `AFHTTPRequestOperation` for downloading and working with XML response data. + + ## Acceptable Content Types + + By default, `AFXMLRequestOperation` accepts the following MIME types, which includes the official standard, `application/xml`, as well as other commonly-used types: + + - `application/xml` + - `text/xml` + + ## Use With AFHTTPClient + + When `AFXMLRequestOperation` is registered with `AFHTTPClient`, the response object in the success callback of `HTTPRequestOperationWithRequest:success:failure:` will be an instance of `NSXMLParser`. On platforms that support `NSXMLDocument`, you have the option to ignore the response object, and simply use the `responseXMLDocument` property of the operation argument of the callback. + */ +@interface AFXMLRequestOperation : AFHTTPRequestOperation + +///---------------------------- +/// @name Getting Response Data +///---------------------------- + +/** + An `NSXMLParser` object constructed from the response data. + */ +@property (readonly, nonatomic, strong) NSXMLParser *responseXMLParser; + +#ifdef __MAC_OS_X_VERSION_MIN_REQUIRED +/** + An `NSXMLDocument` object constructed from the response data. If an error occurs while parsing, `nil` will be returned, and the `error` property will be set to the error. + */ +@property (readonly, nonatomic, strong) NSXMLDocument *responseXMLDocument; +#endif + +/** + Creates and returns an `AFXMLRequestOperation` object and sets the specified success and failure callbacks. + + @param urlRequest The request object to be loaded asynchronously during execution of the operation + @param success A block object to be executed when the operation finishes successfully. This block has no return value and takes three arguments: the request sent from the client, the response received from the server, and the XML parser constructed with the response data of request. + @param failure A block object to be executed when the operation finishes unsuccessfully. This block has no return value and takes three arguments: the request sent from the client, the response received from the server, and the error describing the network error that occurred. + + @return A new XML request operation + */ ++ (instancetype)XMLParserRequestOperationWithRequest:(NSURLRequest *)urlRequest + success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSXMLParser *XMLParser))success + failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, NSXMLParser *XMLParser))failure; + + +#ifdef __MAC_OS_X_VERSION_MIN_REQUIRED +/** + Creates and returns an `AFXMLRequestOperation` object and sets the specified success and failure callbacks. + + @param urlRequest The request object to be loaded asynchronously during execution of the operation + @param success A block object to be executed when the operation finishes successfully. This block has no return value and takes three arguments: the request sent from the client, the response received from the server, and the XML document created from the response data of request. + @param failure A block object to be executed when the operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data as XML. This block has no return value and takes three arguments: the request sent from the client, the response received from the server, and the error describing the network or parsing error that occurred. + + @return A new XML request operation + */ ++ (instancetype)XMLDocumentRequestOperationWithRequest:(NSURLRequest *)urlRequest + success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSXMLDocument *document))success + failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, NSXMLDocument *document))failure; +#endif + +@end diff --git a/Pods/AFNetworking/AFNetworking/AFXMLRequestOperation.m b/Pods/AFNetworking/AFNetworking/AFXMLRequestOperation.m new file mode 100644 index 0000000..a97cd88 --- /dev/null +++ b/Pods/AFNetworking/AFNetworking/AFXMLRequestOperation.m @@ -0,0 +1,167 @@ +// AFXMLRequestOperation.m +// +// Copyright (c) 2011 Gowalla (http://gowalla.com/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "AFXMLRequestOperation.h" + +#include + +static dispatch_queue_t xml_request_operation_processing_queue() { + static dispatch_queue_t af_xml_request_operation_processing_queue; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + af_xml_request_operation_processing_queue = dispatch_queue_create("com.alamofire.networking.xml-request.processing", DISPATCH_QUEUE_CONCURRENT); + }); + + return af_xml_request_operation_processing_queue; +} + +@interface AFXMLRequestOperation () +@property (readwrite, nonatomic, strong) NSXMLParser *responseXMLParser; +#ifdef __MAC_OS_X_VERSION_MIN_REQUIRED +@property (readwrite, nonatomic, strong) NSXMLDocument *responseXMLDocument; +#endif +@property (readwrite, nonatomic, strong) NSError *XMLError; +@end + +@implementation AFXMLRequestOperation +@synthesize responseXMLParser = _responseXMLParser; +#ifdef __MAC_OS_X_VERSION_MIN_REQUIRED +@synthesize responseXMLDocument = _responseXMLDocument; +#endif +@synthesize XMLError = _XMLError; + ++ (instancetype)XMLParserRequestOperationWithRequest:(NSURLRequest *)urlRequest + success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSXMLParser *XMLParser))success + failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, NSXMLParser *XMLParser))failure +{ + AFXMLRequestOperation *requestOperation = [(AFXMLRequestOperation *)[self alloc] initWithRequest:urlRequest]; + [requestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) { + if (success) { + success(operation.request, operation.response, responseObject); + } + } failure:^(AFHTTPRequestOperation *operation, NSError *error) { + if (failure) { + failure(operation.request, operation.response, error, [(AFXMLRequestOperation *)operation responseXMLParser]); + } + }]; + + return requestOperation; +} + +#ifdef __MAC_OS_X_VERSION_MIN_REQUIRED ++ (instancetype)XMLDocumentRequestOperationWithRequest:(NSURLRequest *)urlRequest + success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSXMLDocument *document))success + failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, NSXMLDocument *document))failure +{ + AFXMLRequestOperation *requestOperation = [[self alloc] initWithRequest:urlRequest]; + [requestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, __unused id responseObject) { + if (success) { + NSXMLDocument *XMLDocument = [(AFXMLRequestOperation *)operation responseXMLDocument]; + success(operation.request, operation.response, XMLDocument); + } + } failure:^(AFHTTPRequestOperation *operation, NSError *error) { + if (failure) { + NSXMLDocument *XMLDocument = [(AFXMLRequestOperation *)operation responseXMLDocument]; + failure(operation.request, operation.response, error, XMLDocument); + } + }]; + + return requestOperation; +} +#endif + + +- (NSXMLParser *)responseXMLParser { + if (!_responseXMLParser && [self.responseData length] > 0 && [self isFinished]) { + self.responseXMLParser = [[NSXMLParser alloc] initWithData:self.responseData]; + } + + return _responseXMLParser; +} + +#ifdef __MAC_OS_X_VERSION_MIN_REQUIRED +- (NSXMLDocument *)responseXMLDocument { + if (!_responseXMLDocument && [self.responseData length] > 0 && [self isFinished]) { + NSError *error = nil; + self.responseXMLDocument = [[NSXMLDocument alloc] initWithData:self.responseData options:0 error:&error]; + self.XMLError = error; + } + + return _responseXMLDocument; +} +#endif + +- (NSError *)error { + if (_XMLError) { + return _XMLError; + } else { + return [super error]; + } +} + +#pragma mark - NSOperation + +- (void)cancel { + [super cancel]; + + self.responseXMLParser.delegate = nil; +} + +#pragma mark - AFHTTPRequestOperation + ++ (NSSet *)acceptableContentTypes { + return [NSSet setWithObjects:@"application/xml", @"text/xml", nil]; +} + ++ (BOOL)canProcessRequest:(NSURLRequest *)request { + return [[[request URL] pathExtension] isEqualToString:@"xml"] || [super canProcessRequest:request]; +} + +- (void)setCompletionBlockWithSuccess:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success + failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure +{ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warc-retain-cycles" +#pragma clang diagnostic ignored "-Wgnu" + self.completionBlock = ^ { + dispatch_async(xml_request_operation_processing_queue(), ^(void) { + NSXMLParser *XMLParser = self.responseXMLParser; + + if (self.error) { + if (failure) { + dispatch_async(self.failureCallbackQueue ?: dispatch_get_main_queue(), ^{ + failure(self, self.error); + }); + } + } else { + if (success) { + dispatch_async(self.successCallbackQueue ?: dispatch_get_main_queue(), ^{ + success(self, XMLParser); + }); + } + } + }); + }; +#pragma clang diagnostic pop +} + +@end diff --git a/Pods/AFNetworking/AFNetworking/UIImageView+AFNetworking.h b/Pods/AFNetworking/AFNetworking/UIImageView+AFNetworking.h new file mode 100644 index 0000000..bafb790 --- /dev/null +++ b/Pods/AFNetworking/AFNetworking/UIImageView+AFNetworking.h @@ -0,0 +1,78 @@ +// UIImageView+AFNetworking.h +// +// Copyright (c) 2011 Gowalla (http://gowalla.com/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "AFImageRequestOperation.h" + +#import + +#if __IPHONE_OS_VERSION_MIN_REQUIRED +#import + +/** + This category adds methods to the UIKit framework's `UIImageView` class. The methods in this category provide support for loading remote images asynchronously from a URL. + */ +@interface UIImageView (AFNetworking) + +/** + Creates and enqueues an image request operation, which asynchronously downloads the image from the specified URL, and sets it the request is finished. Any previous image request for the receiver will be cancelled. If the image is cached locally, the image is set immediately, otherwise the specified placeholder image will be set immediately, and then the remote image will be set once the request is finished. + + By default, URL requests have a cache policy of `NSURLCacheStorageAllowed` and a timeout interval of 30 seconds, and are set not handle cookies. To configure URL requests differently, use `setImageWithURLRequest:placeholderImage:success:failure:` + + @param url The URL used for the image request. + */ +- (void)setImageWithURL:(NSURL *)url; + +/** + Creates and enqueues an image request operation, which asynchronously downloads the image from the specified URL. Any previous image request for the receiver will be cancelled. If the image is cached locally, the image is set immediately, otherwise the specified placeholder image will be set immediately, and then the remote image will be set once the request is finished. + + By default, URL requests have a cache policy of `NSURLCacheStorageAllowed` and a timeout interval of 30 seconds, and are set not handle cookies. To configure URL requests differently, use `setImageWithURLRequest:placeholderImage:success:failure:` + + @param url The URL used for the image request. + @param placeholderImage The image to be set initially, until the image request finishes. If `nil`, the image view will not change its image until the image request finishes. + */ +- (void)setImageWithURL:(NSURL *)url + placeholderImage:(UIImage *)placeholderImage; + +/** + Creates and enqueues an image request operation, which asynchronously downloads the image with the specified URL request object. Any previous image request for the receiver will be cancelled. If the image is cached locally, the image is set immediately, otherwise the specified placeholder image will be set immediately, and then the remote image will be set once the request is finished. + + If a success block is specified, it is the responsibility of the block to set the image of the image view before returning. If no success block is specified, the default behavior of setting the image with `self.image = image` is executed. + + @param urlRequest The URL request used for the image request. + @param placeholderImage The image to be set initially, until the image request finishes. If `nil`, the image view will not change its image until the image request finishes. + @param success A block to be executed when the image request operation finishes successfully, with a status code in the 2xx range, and with an acceptable content type (e.g. `image/png`). This block has no return value and takes three arguments: the request sent from the client, the response received from the server, and the image created from the response data of request. If the image was returned from cache, the request and response parameters will be `nil`. + @param failure A block object to be executed when the image request operation finishes unsuccessfully, or that finishes successfully. This block has no return value and takes three arguments: the request sent from the client, the response received from the server, and the error object describing the network or parsing error that occurred. + */ +- (void)setImageWithURLRequest:(NSURLRequest *)urlRequest + placeholderImage:(UIImage *)placeholderImage + success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image))success + failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error))failure; + +/** + Cancels any executing image request operation for the receiver, if one exists. + */ +- (void)cancelImageRequestOperation; + +@end + +#endif diff --git a/Pods/AFNetworking/AFNetworking/UIImageView+AFNetworking.m b/Pods/AFNetworking/AFNetworking/UIImageView+AFNetworking.m new file mode 100644 index 0000000..839a2b8 --- /dev/null +++ b/Pods/AFNetworking/AFNetworking/UIImageView+AFNetworking.m @@ -0,0 +1,191 @@ +// UIImageView+AFNetworking.m +// +// Copyright (c) 2011 Gowalla (http://gowalla.com/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import + +#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) +#import "UIImageView+AFNetworking.h" + +@interface AFImageCache : NSCache +- (UIImage *)cachedImageForRequest:(NSURLRequest *)request; +- (void)cacheImage:(UIImage *)image + forRequest:(NSURLRequest *)request; +@end + +#pragma mark - + +static char kAFImageRequestOperationObjectKey; + +@interface UIImageView (_AFNetworking) +@property (readwrite, nonatomic, strong, setter = af_setImageRequestOperation:) AFImageRequestOperation *af_imageRequestOperation; +@end + +@implementation UIImageView (_AFNetworking) +@dynamic af_imageRequestOperation; +@end + +#pragma mark - + +@implementation UIImageView (AFNetworking) + +- (AFHTTPRequestOperation *)af_imageRequestOperation { + return (AFHTTPRequestOperation *)objc_getAssociatedObject(self, &kAFImageRequestOperationObjectKey); +} + +- (void)af_setImageRequestOperation:(AFImageRequestOperation *)imageRequestOperation { + objc_setAssociatedObject(self, &kAFImageRequestOperationObjectKey, imageRequestOperation, OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + ++ (NSOperationQueue *)af_sharedImageRequestOperationQueue { + static NSOperationQueue *_af_imageRequestOperationQueue = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + _af_imageRequestOperationQueue = [[NSOperationQueue alloc] init]; + [_af_imageRequestOperationQueue setMaxConcurrentOperationCount:NSOperationQueueDefaultMaxConcurrentOperationCount]; + }); + + return _af_imageRequestOperationQueue; +} + ++ (AFImageCache *)af_sharedImageCache { + static AFImageCache *_af_imageCache = nil; + static dispatch_once_t oncePredicate; + dispatch_once(&oncePredicate, ^{ + _af_imageCache = [[AFImageCache alloc] init]; + }); + + return _af_imageCache; +} + +#pragma mark - + +- (void)setImageWithURL:(NSURL *)url { + [self setImageWithURL:url placeholderImage:nil]; +} + +- (void)setImageWithURL:(NSURL *)url + placeholderImage:(UIImage *)placeholderImage +{ + NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; + [request addValue:@"image/*" forHTTPHeaderField:@"Accept"]; + + [self setImageWithURLRequest:request placeholderImage:placeholderImage success:nil failure:nil]; +} + +- (void)setImageWithURLRequest:(NSURLRequest *)urlRequest + placeholderImage:(UIImage *)placeholderImage + success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image))success + failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error))failure +{ + [self cancelImageRequestOperation]; + + UIImage *cachedImage = [[[self class] af_sharedImageCache] cachedImageForRequest:urlRequest]; + if (cachedImage) { + self.af_imageRequestOperation = nil; + + if (success) { + success(nil, nil, cachedImage); + } else { + self.image = cachedImage; + } + } else { + if (placeholderImage) { + self.image = placeholderImage; + } + + AFImageRequestOperation *requestOperation = [[AFImageRequestOperation alloc] initWithRequest:urlRequest]; + +#ifdef _AFNETWORKING_ALLOW_INVALID_SSL_CERTIFICATES_ + requestOperation.allowsInvalidSSLCertificate = YES; +#endif + + [requestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) { + if ([urlRequest isEqual:[self.af_imageRequestOperation request]]) { + if (self.af_imageRequestOperation == operation) { + self.af_imageRequestOperation = nil; + } + + if (success) { + success(operation.request, operation.response, responseObject); + } else if (responseObject) { + self.image = responseObject; + } + } + + [[[self class] af_sharedImageCache] cacheImage:responseObject forRequest:urlRequest]; + } failure:^(AFHTTPRequestOperation *operation, NSError *error) { + if ([urlRequest isEqual:[self.af_imageRequestOperation request]]) { + if (self.af_imageRequestOperation == operation) { + self.af_imageRequestOperation = nil; + } + + if (failure) { + failure(operation.request, operation.response, error); + } + } + }]; + + self.af_imageRequestOperation = requestOperation; + + [[[self class] af_sharedImageRequestOperationQueue] addOperation:self.af_imageRequestOperation]; + } +} + +- (void)cancelImageRequestOperation { + [self.af_imageRequestOperation cancel]; + self.af_imageRequestOperation = nil; +} + +@end + +#pragma mark - + +static inline NSString * AFImageCacheKeyFromURLRequest(NSURLRequest *request) { + return [[request URL] absoluteString]; +} + +@implementation AFImageCache + +- (UIImage *)cachedImageForRequest:(NSURLRequest *)request { + switch ([request cachePolicy]) { + case NSURLRequestReloadIgnoringCacheData: + case NSURLRequestReloadIgnoringLocalAndRemoteCacheData: + return nil; + default: + break; + } + + return [self objectForKey:AFImageCacheKeyFromURLRequest(request)]; +} + +- (void)cacheImage:(UIImage *)image + forRequest:(NSURLRequest *)request +{ + if (image && request) { + [self setObject:image forKey:AFImageCacheKeyFromURLRequest(request)]; + } +} + +@end + +#endif diff --git a/Pods/AFNetworking/LICENSE b/Pods/AFNetworking/LICENSE new file mode 100644 index 0000000..0616192 --- /dev/null +++ b/Pods/AFNetworking/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2013-2014 AFNetworking (http://afnetworking.com/) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/Pods/AFNetworking/README.md b/Pods/AFNetworking/README.md new file mode 100644 index 0000000..da30989 --- /dev/null +++ b/Pods/AFNetworking/README.md @@ -0,0 +1,206 @@ +

+ AFNetworking +

+ +AFNetworking is a delightful networking library for iOS and Mac OS X. It's built on top of [NSURLConnection](http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSURLConnection_Class/Reference/Reference.html), [NSOperation](http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/NSOperation_class/Reference/Reference.html), and other familiar Foundation technologies. It has a modular architecture with well-designed, feature-rich APIs that are a joy to use. For example, here's how easy it is to get JSON from a URL: + +```objective-c +NSURL *url = [NSURL URLWithString:@"https://alpha-api.app.net/stream/0/posts/stream/global"]; +NSURLRequest *request = [NSURLRequest requestWithURL:url]; +AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) { + NSLog(@"App.net Global Stream: %@", JSON); +} failure:nil]; +[operation start]; +``` + +Perhaps the most important feature of all, however, is the amazing community of developers who use and contribute to AFNetworking every day. AFNetworking powers some of the most popular and critically-acclaimed apps on the iPhone, iPad, and Mac. + +Choose AFNetworking for your next project, or migrate over your existing projects—you'll be happy you did! + +## How To Get Started + +- [Download AFNetworking](https://github.com/AFNetworking/AFNetworking/zipball/master) and try out the included Mac and iPhone example apps +- Read the ["Getting Started" guide](https://github.com/AFNetworking/AFNetworking/wiki/Getting-Started-with-AFNetworking), [FAQ](https://github.com/AFNetworking/AFNetworking/wiki/AFNetworking-FAQ), or [other articles in the wiki](https://github.com/AFNetworking/AFNetworking/wiki) +- Check out the [complete documentation](http://cocoadocs.org/docsets/AFNetworking/) for a comprehensive look at the APIs available in AFNetworking +- Watch the [NSScreencast episode about AFNetworking](http://nsscreencast.com/episodes/6-afnetworking) for a quick introduction to how to use it in your application +- Questions? [Stack Overflow](http://stackoverflow.com/questions/tagged/afnetworking) is the best place to find answers + +## Overview + +AFNetworking is architected to be as small and modular as possible, in order to make it simple to use and extend. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Core
AFURLConnectionOperationAn NSOperation that implements the NSURLConnection delegate methods.
HTTP Requests
AFHTTPRequestOperationA subclass of AFURLConnectionOperation for requests using the HTTP or HTTPS protocols. It encapsulates the concept of acceptable status codes and content types, which determine the success or failure of a request.
AFJSONRequestOperationA subclass of AFHTTPRequestOperation for downloading and working with JSON response data.
AFXMLRequestOperationA subclass of AFHTTPRequestOperation for downloading and working with XML response data.
AFPropertyListRequestOperationA subclass of AFHTTPRequestOperation for downloading and deserializing objects with property list response data.
HTTP Client
AFHTTPClient + Captures the common patterns of communicating with an web application over HTTP, including: + +
    +
  • Making requests from relative paths of a base URL
  • +
  • Setting HTTP headers to be added automatically to requests
  • +
  • Authenticating requests with HTTP Basic credentials or an OAuth token
  • +
  • Managing an NSOperationQueue for requests made by the client
  • +
  • Generating query strings or HTTP bodies from an NSDictionary
  • +
  • Constructing multipart form requests
  • +
  • Automatically parsing HTTP response data into its corresponding object representation
  • +
  • Monitoring and responding to changes in network reachability
  • +
+
Images
AFImageRequestOperationA subclass of AFHTTPRequestOperation for downloading and processing images.
UIImageView+AFNetworkingAdds methods to UIImageView for loading remote images asynchronously from a URL.
+ +## Example Usage + +### XML Request + +```objective-c +NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://api.flickr.com/services/rest/?method=flickr.groups.browse&api_key=b6300e17ad3c506e706cb0072175d047&cat_id=34427469792%40N01&format=rest"]]; +AFXMLRequestOperation *operation = [AFXMLRequestOperation XMLParserRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, NSXMLParser *XMLParser) { + XMLParser.delegate = self; + [XMLParser parse]; +} failure:nil]; +[operation start]; +``` + +### Image Request + +```objective-c +UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 100.0f, 100.0f)]; +[imageView setImageWithURL:[NSURL URLWithString:@"http://i.imgur.com/r4uwx.jpg"] placeholderImage:[UIImage imageNamed:@"placeholder-avatar"]]; +``` + +### API Client Request + +```objective-c +// AFAppDotNetAPIClient is a subclass of AFHTTPClient, which defines the base URL and default HTTP headers for NSURLRequests it creates +[[AFAppDotNetAPIClient sharedClient] getPath:@"stream/0/posts/stream/global" parameters:nil success:^(AFHTTPRequestOperation *operation, id JSON) { + NSLog(@"App.net Global Stream: %@", JSON); +} failure:nil]; +``` + +### File Upload with Progress Callback + +```objective-c +NSURL *url = [NSURL URLWithString:@"http://api-base-url.com"]; +AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:url]; +NSData *imageData = UIImageJPEGRepresentation([UIImage imageNamed:@"avatar.jpg"], 0.5); +NSMutableURLRequest *request = [httpClient multipartFormRequestWithMethod:@"POST" path:@"/upload" parameters:nil constructingBodyWithBlock: ^(id formData) { + [formData appendPartWithFileData:imageData name:@"avatar" fileName:@"avatar.jpg" mimeType:@"image/jpeg"]; +}]; + +AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request]; +[operation setUploadProgressBlock:^(NSUInteger bytesWritten, long long totalBytesWritten, long long totalBytesExpectedToWrite) { + NSLog(@"Sent %lld of %lld bytes", totalBytesWritten, totalBytesExpectedToWrite); +}]; +[httpClient enqueueHTTPRequestOperation:operation]; +``` + +### Streaming Request + +```objective-c +NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://localhost:8080/encode"]]; + +AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request]; +operation.inputStream = [NSInputStream inputStreamWithFileAtPath:[[NSBundle mainBundle] pathForResource:@"large-image" ofType:@"tiff"]]; +operation.outputStream = [NSOutputStream outputStreamToMemory]; +[operation start]; +``` + +## Requirements + +AFNetworking 1.0 and higher requires either [iOS 5.0](http://developer.apple.com/library/ios/#releasenotes/General/WhatsNewIniPhoneOS/Articles/iPhoneOS4.html) and above, or [Mac OS 10.7](http://developer.apple.com/library/mac/#releasenotes/MacOSX/WhatsNewInOSX/Articles/MacOSX10_6.html#//apple_ref/doc/uid/TP40008898-SW7) ([64-bit with modern Cocoa runtime](https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtVersionsPlatforms.html)) and above. + +For compatibility with iOS 4.3, use the latest 0.10.x release. + +### ARC + +AFNetworking uses ARC as of its 1.0 release. + +If you are using AFNetworking 1.0 in your non-arc project, you will need to set a `-fobjc-arc` compiler flag on all of the AFNetworking source files. Conversely, if you are adding a pre-1.0 version of AFNetworking, you will need to set a `-fno-objc-arc` compiler flag. + +To set a compiler flag in Xcode, go to your active target and select the "Build Phases" tab. Now select all AFNetworking source files, press Enter, insert `-fobjc-arc` or `-fno-objc-arc` and then "Done" to enable or disable ARC for AFNetworking. + +## Unit Tests + +AFNetworking includes a suite of unit tests within the Tests subdirectory. In order to run the unit tests, you must install the testing dependencies via CocoaPods. To do so: + + $ gem install cocoapods # If necessary + $ cd Tests + $ pod install + +Once CocoaPods has finished the installation, you can execute the test suite via the 'iOS Tests' and 'OS X Tests' schemes within Xcode. + +### Test Logging + +By default, the unit tests do not emit any output during execution. For debugging purposes, it can be useful to enable logging of the requests and responses. Logging support is provided by the [AFHTTPRequestOperationLogger](https://github.com/AFNetworking/AFHTTPRequestOperationLogger) extension, which is installed via CocoaPods into the test targets. To enable logging, edit the test Scheme and add an environment variable named `AFTestsLoggingEnabled` with a value of `YES`. + +### Using xctool + +If you wish to execute the tests from the command line or within a continuous integration environment, you will need to install [xctool](https://github.com/facebook/xctool). The recommended installation method is [Homebrew](http://mxcl.github.io/homebrew/). + +To install the commandline testing support via Homebrew: + + $ brew update + $ brew install xctool --HEAD + +Once xctool is installed, you can execute the suite via `rake test`. + +## Credits + +AFNetworking was created by [Scott Raymond](https://github.com/sco/) and [Mattt Thompson](https://github.com/mattt/) in the development of [Gowalla for iPhone](http://en.wikipedia.org/wiki/Gowalla). + +AFNetworking's logo was designed by [Alan Defibaugh](http://www.alandefibaugh.com/). + +And most of all, thanks to AFNetworking's [growing list of contributors](https://github.com/AFNetworking/AFNetworking/contributors). + +## Contact + +Follow AFNetworking on Twitter ([@AFNetworking](https://twitter.com/AFNetworking)) + +### Creators + +[Mattt Thompson](http://github.com/mattt) +[@mattt](https://twitter.com/mattt) + +[Scott Raymond](http://github.com/sco) +[@sco](https://twitter.com/sco) + +## License + +AFNetworking is available under the MIT license. See the LICENSE file for more info. diff --git a/Pods/GoogleMaps/CHANGELOG b/Pods/GoogleMaps/CHANGELOG new file mode 100644 index 0000000..ca34c2f --- /dev/null +++ b/Pods/GoogleMaps/CHANGELOG @@ -0,0 +1,468 @@ +Version 1.10.3 - September 2015 +=============================== +Features: + - Google logos have been updated. + +Resolved Issues: + - Framework now ships with the device version of bundles to pass Xcode 7 archive checks. + +Version 1.10.2 - August 2015 +============================ +Resolved Issues: + - Fixed a crash releasing a map view while in background. + - Resolved a conflict with apps using gtm-session-fetcher resumable downloads. + - Recompiled with Xcode 6.4 to avoid some bugs in Xcode 6.3 compiler. + - Updated GoogleMaps.bundle info.plist to avoid triggering new checks in + pre-submission verification. + +Version 1.10.1 - June 2015 +========================== +Resolved Issues: + - Fixed an issue where instantiating GMSPlacesClient triggered a request to enable Bluetooth. + - Miscellaneous improvements to the GMSPlacePicker UI. + +Version 1.10.0 - May 2015 +========================= +Major Feature: + - Places API is now bundled with the Google Maps SDK for iOS. + +Features: + - New allowScrollGesturesDuringRotateOrZoom property on GMSUISettings controls whether + the user can scroll by panning during multi-touch rotate or zoom gestures. + - GMSPanoramaView now supports being used via storyboard. + - GMSGeocoder now supports being used while the application is in the background. + - GMSServices sharedServices can now be called while application is in the background. Note + that if the first call to sharedServices is while application is in the background some + async initialization work will be deferred until the first time a map is shown where it will + be performed synchronously. + - GMSMapView/GMSPanoramaView init messages can now be handled while the application is in + background. This should remove the last case where GMSMapView/GMSPanoramaView could not + be used in the background. + - GMSMapView/GMSPanormaView delegate properties now support IBOutlet for easier use via + storyboard. + +Resolved Issues: + - mapView:didTapMyLocationButtonForMapView: is now correctly called even if no location is + available. + - GMSGroundOverlay now shows correctly when rotated if image aspect ratio doesn't match the + selected ground region. + - Fixed an issue resizing the map on iOS 8. + - Fixed a rare crash under fast camera changes. + - Map no longer hangs when adding a ground overlay with certain invalid bounds. + - Fixed a crash when texture memory is exhausted by markers. + - Correctly return the tapped GMSCircle to mapView:didTapOverlay: for tappable circles. + - mapView:idleAtCameraPosition: will now be called even if there is an ongoing update of the + my location dot. + +Notes: + - Due to an ABI change in the Xcode compiler, Xcode 6.3 is now the only supported version for + compiling against Google Maps SDK for iOS. + - The minimum target iOS version for Google Maps SDK for iOS is now 7.0. Version 6.0 is no + longer supported. + +Version 1.9.2 - February 2015 +============================= +Resolved Issues: + - Show correct characters for Myanmar place labels. + - Fixed small memory leak related to font registration. + - Fixed large memory leak in rare cases where My Location is enabled and the user rotates + the screen. + - Correctly show ground overlays defined by zoom level which extend across >180 degrees + of longitude. + - Allow selected marker to be set during mapView:didTapAtCoordinate:. + - Throw exception rather than crash when map services are initialized while application is + in background. + - Raise mapView:willMove: and mapView:idleAtCameraPosition: even for swipe motions which + last less than 30ms. + - Correctly handle animations starting while a gesture is decelerating. + - Always return an error from GMSPanoramaService callbacks if panorama is nil. + - Don't attempt to navigate to empty panorama if moveNearCoordinate: resolves to nil. + +Version 1.9.1 - December 2014 +============================= +Resolved Issues: + - Added workaround for userEmail private selector false positive. + - Improved handling of info windows for iPhone 6+ running applications in scaled mode. + +Version 1.9.0 - October 2014 +============================ +Features: + - Support for iOS 8 + - Support for iPhone 6/6+ + - Support for Swift + - UI elements have been updated for material design + +Resolved Issues: + - Fixed some memory reclamation issues + - Improved handling of application background state transition + +Notes: + ! In order to improve compatibility with Swift, two geometry library + functions have been renamed to avoid function overloading + The new names are GMSGeometryIsLocationOnPathTolerance and + GMSStyleSpansOffset + +Version 1.8.1 - May 2014 +======================== +Resolved Issues: + - Resolved GMSTileLayer not displaying + - Resolved a rare case where an app would crash when displaying polylines + while accessibility features are enabled + - mapView:willMove: is no longer called alongside a tap gesture + - Resolved symbol collisions with the Protocol Buffer library + +Version 1.8.0 - May 2014 +======================== +Resolved Issues: + - Resolved threading deadlock prominent on iPhone 4 running iOS 7.1 or later + - GMSMapView correctly releases some shared GL state previously causing + memory leak + - GMSPolyline no longer crashes in some cases where its path contained more + than 1024 segments + - The delegate method mapView:idleAtCameraPosition: is now only called once + all user gestures are complete + - The Google Maps SDK for iOS now includes fonts for languages currently + unsupported by the iOS system, such as Khmer + - These fonts may be safely removed from your GoogleMaps.framework if you + have no interest in these regions, but some text may render as "[?]" + +Version 1.7.2 - March 2014 +========================== +Resolved Issues: + - Heading will only appear on My Location dot when available + - Better reduction of colors on gradient or colored polylines at low zoom + - The search radius is now respected when retrieving a GMSPanorama object + via GMSPanoramaService and on GMSPanoramaView construction or move + - GMSPolyline is no longer grayscale on iOS 7.1 + +Version 1.7.0 - February 2014 +============================= +Features: + - Styled polylines: additional color options via GMSPolyline, including + gradients and colors per any number of polyline segments + * Each polyline may be drawn with many GMSStyleSpan instances, configuring + a unique color or gradient over an arbitrary number of segments + * Gradient or color may be specified via a GMSStrokeStyle + * GMSPath provides a helper category to determine distance along a path + * GMSStyleSpans helper to apply repeated styles along a polyline + - GMSGeocoder now provides structured addresses via GMSAddress, deprecating + GMSReverseGeocodeResult + - Added mutable version of GMSCameraPosition, GMSMutableCameraPosition + - Delegate method for user tapping the My Location button + - Added GMSMapPoint for linear interpolation between points in Mercator space + on the Earth + - My Location dot now shows compass arrow + - 3D building data at many places on the Earth + +Resolved Issues: + - GMSPolyline width is much closer to screen width + - GMSPolyline performance and memory improvements + - Reduced memory use of OpenGL textures + - Floor picker is positioned correctly when My Location button is disabled + - cameraForBounds:insets: on GMSMapView now correctly accounts for padding + +Notes: + ! To align with other Google Maps APIs, GMSMapView no longer provides helper + methods to retrieve previously added overlays, such as -markers, -polylines + and -groundOverlays + +Version 1.6.2 - January 2014 +============================ +Resolved Issues: + - Resolved a gesture bug effecting full-screen maps on iOS 7 + - Resolved an issue where overlays were sometimes not initially tappable + +Version 1.6.1 - December 2013 +============================= +Resolved Issues: + - Resolved a memory leak involving vector tiles + - Markers not immediately added to a GMSMapView no longer fail to appear + when configured at a later point + - GMSMapView/GMSPanoramaView will now continue to render while your + application is resigned + +Version 1.6.0 - November 2013 +============================= +Features: + - The Google Maps SDK for iOS now supports 64-bit architectures + - Added the ability to restrict min and max zoom on GMSMapView + - Added opacity on GMSTileLayer + - Added opacity on GMSMarker, which may be animated + ! Updated types within the SDK and used float or double instead of CGFloat + in cases where it was more appropriate + ! Core Animation on GMSMapView now requires model values to be set + +Resolved Issues: + - Marker info windows and tappable regions now rotate correctly with markers + - Padding on a GMSMapView is no longer clamped to its bounds (useful if + setting padding on an initially zero-sized map) + - Copyright information now animates alongside changing GMSMapView size or + padding + - Info windows are removed if their GMSMarker is removed from a GMSMapView + - My Location dot uses the last known information when enabled + - Resolved two rare race conditions that were causing crashes + - Resolved an issue where retain cycles were causing memory leaks on + GMSMapView and GMSPanoramaView + +Version 1.5.0 - September 2013 +============================== +Features: + ! This release officially supports iOS 7, and requires iOS 6.0 or later (iOS + 5.1 is no longer supported). + ! The 'animated' field on GMSMarker is now known as 'appearAnimation', and + may be set to kGMSMarkerAnimationNone (default) or kGMSMarkerAnimationPop + - The Google Maps SDK for iOS now ships with an armv7s slice + - New features for GMSMarker instances + * Markers can be made draggable using the draggable property, and new drag + delegate methods have been added to GMSMapViewDelegate + * Added GMSMarkerLayer, a custom CALayer subclass for GMSMarker that + supports animation of marker position and rotation + * Added support for markers that appear flat against the Earth's surface + * Added rotation property to rotate markers around their ground anchor + * The UIImage used by GMSMarker now supports the images and duration + properties, and will animate images with multiple frames + * The UIImage used by GMSMarker now supports alignmentRectInsets, and will + adjust groundAnchor, infoWindowAnchor, and the tappable region + - Added padding on GMSMapView, allowing you to indicate parts of the map that + may be obscured by other views; setting padding re-positions the standard + map controls, and the camera and camera updates will use the padded region + - GMSPanoramaView and GMSPanoramaService now support searching for panoramas + with custom radius + - Added cameraForBounds:insets: to GMSMapView, allowing construction of a + GMSCameraPosition for the map from a specified GMSCoordinateBounds + +Resolved Issues: + - My Location button now clips within GMSMapView + - Reduced memory usage of GMSMapView through less agressive tile caching + - Reduced the time taken to obtain GMSServices by moving some startup tasks + to a background thread; obtaining this object early in your application + (before creating a GMSMapView or other objects) may improve performance + - Polylines may now be drawn twice, as required, if they have very large + longitudinal span + - Resolved a rounding error with very small polygons far from latlng (0,0) + +Version 1.4.3 - August 2013 +=========================== +Resolved Issues: + - Resolved several causes of modifying markers that could cause 'ghost' + markers to appear + - Resolved excess texture use when modifying animated markers + +Version 1.4.2 - August 2013 +=========================== +Resolved Issues: + - Fixed a rare case where modifying an animated marker could cause 'ghost' + markers to appear + - Prioritized markers over other overlays for tappability + +Version 1.4.1 - August 2013 +=========================== +Features: + - Tappable markers inside GMSPanoramaView using the + panoramaView:didTapMarker: delegate method on GMSPanoramaViewDelegate + - Added GMSPanoramaLayer, a custom CALayer subclass for GMSPanoramaView that + supports animation of the panorama camera + - GMSPanoramaCamera supports custom field of view (FOV) + - Programmatic access to the floor picker allows you to enable or disable the + selector, and set which floor should be displayed + - GMSTileLayer now supports high DPI tiles, for use on a Retina device + - GMSMapView.camera is now observable via KVO + - Added fitBounds:withEdgeInsets: to GMSCameraUpdate + - The default behavior of a GMSMapView to consume all gestures within its + bounds may now be disabled via consumesGesturesInView + - Expanded GMSGeometryUtils to include additional helper methods + - GMSServices may be held by applications to maintain cache and connection to + Google; this can improve performance when creating and destroying many maps + - Improved visuals when resizing a GMSMapView via UIView animation methods + +Resolved Issues: + - Fixed crash bug during memory warning (related to indoor) + - Fixed crash bug with indoor maps on iOS 5.1 + - Performance improvements when using hundreds of GMSMarkers + - Reduced memory footprint of GMSMapView + - Touch target for GMSMarkers matches the size and shape of the marker when + the GMSMapView is tilted + - GMSMapView will no longer render a single frame of black in some cases + (noticable e.g., inside UISplitViewController on iPad) + - Street View imagery is now adjusted correctly for tilted base data + (e.g., data taken by a Street View car on a slope) + - Geodesic interpolation has been tweaked to be more correct + - Fixed incorrect GMSGroundOverlay sizing (regression in 1.4.0) + - fitBounds:withPadding: on GMSCameraUpdate now correctly applies padding to + all edges of the bounds; previously it used 1/2 padding on each edge + +Version 1.4.0 - July 2013 +========================= +Features: + - Support for Google Street View imagery, with coverage in 50+ countries + * Added GMSPanoramaView, a viewer for Street View imagery, that enables + both programmatic and user control + * GMSMarkers can be shared between GMSMapView and GMSPanoramaView + * GMSPanoramaService may be used to load panorama data ahead of display + - Indoor floor plans and a floor selector control will now be displayed when + available + - Updated map design inspired by the new Google Maps + - Info windows now show at 1:1 resolution on the screen regardless of tilt + - Additional delegate methods on GMSMapView - mapView:willMove: and + mapView:idleAtCameraPosition: - allow you to detect the start and + end of camera movement, respectively + - An improved look and feel for polylines and polygon stroke + - Added a zIndex property on all overlays; z-indexes are calculated in two + groups: GMSMarkers and all other overlays + - Added GMSGeometryUtils methods for heading, distance, offset etc. with + respect to points on the Earth + +Resolved Issues: + - Improved the tappability of GMSPolygon + - The compass now disappears when the map returns to zero bearing for any + reason, including animation + - Resolved crash issue when creating a zero-sized GMSPolygon + - Resolved an issue where active gestures could cause a GMSMapView to not + be released until deceleration completed + - Info windows no longer allow taps to pass through them + ! Accessibility elements on GMSMapView are now hidden by default; you can + enable via accessibilityElementsHidden + +Notes: + ! To align with other Google Maps APIs, GMSGroundOverlay no longer supports + the zoomLevel property. You can use the helper method + groundOverlayWithPosition:icon:zoomLevel: to migrate existing code + +Version 1.3.1 - June 2013 +========================= +Resolved Issues: + - Shows all tiles when animating across the antimeridian + - Performance improvements while zooming + - Touches are consumed more agressively by GMSMapView + - Fixed constructing a GMSMutablePath via pathFromEncodedPath: + - Restores OpenGL state correctly in GMSMapView in applications that also use + GLKView + +Version 1.3.0 - May 2013 +======================== +Features: + - Support for custom tile overlays (image-based) via GMSTileLayer + - Anti-aliasing for GMSPolyline and GMSPolygon stroke + - Support for 'invisible' base map tiles via kGMSTypeNone + - Basic support for CAAnimationGroup on GMSMapLayer + +Resolved Issues: + - Performance improvements with large numbers of overlays + - Resolved excessive memory use when device was locked/unlocked while an info + window was displayed + - Animations are stopped when a user performs a gesture + - Animations stop any active gesture (e.g., a pan) + - Resolved crash issue with setting/clearing My Location dot. + - GMSPolyline and GMSPolygon now support greater precision at high zoom + - GMSPolyline and GMSPolygon use the correct alpha values + - Touches are consumed by GMSMapView, allowing use within e.g. a scroll view + +Version 1.2.2 - April 2013 +========================== +Resolved Issues: + - Tappable regions for GMSMarker fixed. + - Overlays are no longer able to render on half pixels. + - Ground overlays appear underneath the My Location dot. + - GMSPolyline 'strokeColor' is no longer erroneously deallocated. + +Version 1.2.0 - April 2013 +========================== +Features: + ! Removed GMS...Options classes in favor of creating overlays directly + and setting their 'map' property + ! Map overlays (GMSMarker, GMSPolyline, others) now inherit from a shared + GMSOverlay class + ! GMSPolyline now has 'strokeWidth' and 'strokeColor' to match GMSPolygon, + rather than 'width' and 'stroke' + ! More helper methods on GMSCoordinateBounds, 'including' renamed to + 'includingCoordinate', added 'includingBounds' + - Added GMSPolygon and GMSCircle overlays + - A GMSMarker may be animated when added to a map + - Overlay types may now be subclassed + - GMSCameraUpdate to create camera update objects, including operations to + set a camera that presents a specified GMSCoordinateBounds + - GMSUISettings may be used to add a compass or My Location button (disabled + by default) + - Non-marker overlay types may be tapped (see GMSMapViewDelegate) + - Default marker changed to the Google Maps for iPhone marker + - Added markerImageWithColor: to create tinted versions of the default marker + - GMSMapLayer, the CALayer subclass for GMSMapView, now supports modification + of its camera properties, allowing for advanced animation effects + +Resolved Issues: + - visibleRegion now reports correctly sized region on Retina devices + - Double-tap to zoom now centers around tapped point + - Disabling pan via UISettings now prevents movement with zoom gestures + - GMSPolyline performance is improved for large polylines + - GMSMapView may be subclassed + - My Location dot appears underneath markers + - Performance improvements when using the My Location dot + - Grayscale polylines now render correctly + - Calling renderInContext: on the GMSMapView layer now renders correctly; + this allows for snapshots and UI effects + - The default behavior when a marker is tapped has been updated to also pan + the camera to the marker's position + - semaphore_wait_trap issue resolved + +Version 1.1.2 - March 2013 +========================== +Resolved Issues: + ! Updated the SDK to use libc++ instead of libstdc++ + - Improved support for including a GMSMapView and GLKView in the same app + +Version 1.1.1 - March 2013 +========================== +Features: + - Improved the messages that are logged to the console when a invalid key is + used or a connection error occurs + - Added multi-line snippet support for GMSMarker + +Resolved Issues: + - GMSMapView could return a nil camera + - Multiple GMSMapView instances no longer 'camera crosstalk.' + - The SDK contained unresolved external references + - A GMSMarker with an empty title and snippet no longer shows an empty + info window. + +Version 1.1.0 - February 2013 +============================= +Features: + ! The points of a GMSPolyline (and GMSPolylineOptions) are now specified as + a GMSPath and built via a GMSMutablePath, rather than addVertex: etc + - GMSPolyline may now be specified as geodesic + - animateToCameraPosition: method on GMSMapView + - GMSProjection provides containsCoordinate: and visibleRegion helpers + +Resolved Issues: + - GMSCameraPosition and animateToLocation: now clamp/wrap latitude/longitude + respectively; similarly, bearing is clamped to 0 <= bearing < 360 + - GMSGroundOverlay may be modified after creation + - The points of a GMSPoyline may be modified after creation + - GMSPolyline may cross the antimeridian + - Resolved a marker sorting issue + +Version 1.0.2 - January 2013 +============================ +Features: + ! GMSCamera (struct) has been dropped in favor of GMSCameraPosition * (objc + class), supports finer control of bearing and viewing angle + - Added GMSUISettings to control gesture availability + - Added GMSGroundOverlay/GMSGroundOverlayOptions for basic ground overlay + support + - Removed requirement to call startRendering/stopRendering + - Support for adding GMSMapView as a custom UIView in Interface Builder + - Improved texture memory handling + +Resolved Issues: + - Info windows now have highest tap priority + - Selected markers are automatically brought to front + - Polylines now render at constant size regardless of the zoom level + +Version 1.0.1 - December 2012 +============================= +Initial release alongside Google Maps for iOS. +Support for 3D maps, rotation, tilt, 3D buildings, markers, polylines, +satellite and terrain tiles, traffic data, and other features. + + +* Items denoted with an '!' may indicate a backwards incompatible change. diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/GoogleMaps b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/GoogleMaps new file mode 120000 index 0000000..17ed6fb --- /dev/null +++ b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/GoogleMaps @@ -0,0 +1 @@ +Versions/Current/GoogleMaps \ No newline at end of file diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Headers b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Headers new file mode 120000 index 0000000..a177d2a --- /dev/null +++ b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Headers @@ -0,0 +1 @@ +Versions/Current/Headers \ No newline at end of file diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Modules b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Modules new file mode 120000 index 0000000..5736f31 --- /dev/null +++ b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Modules @@ -0,0 +1 @@ +Versions/Current/Modules \ No newline at end of file diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Resources b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Resources new file mode 120000 index 0000000..953ee36 --- /dev/null +++ b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Resources @@ -0,0 +1 @@ +Versions/Current/Resources \ No newline at end of file diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/GoogleMaps b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/GoogleMaps new file mode 100644 index 0000000..fbf6c95 Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/GoogleMaps differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSAddress.h b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSAddress.h new file mode 100644 index 0000000..e9b1a87 --- /dev/null +++ b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSAddress.h @@ -0,0 +1,69 @@ +// +// GMSAddress.h +// Google Maps SDK for iOS +// +// Copyright 2014 Google Inc. +// +// Usage of this SDK is subject to the Google Maps/Google Earth APIs Terms of +// Service: https://developers.google.com/maps/terms +// + +#import + +#import + +/** + * A result from a reverse geocode request, containing a human-readable address. This class is + * immutable and should be obtained via GMSGeocoder. + * + * Some of the fields may be nil, indicating they are not present. + */ +@interface GMSAddress : NSObject + +/** Location, or kLocationCoordinate2DInvalid if unknown. */ +@property(nonatomic, readonly) CLLocationCoordinate2D coordinate; + +/** Street number and name. */ +@property(nonatomic, copy, readonly) NSString *thoroughfare; + +/** Locality or city. */ +@property(nonatomic, copy, readonly) NSString *locality; + +/** Subdivision of locality, district or park. */ +@property(nonatomic, copy, readonly) NSString *subLocality; + +/** Region/State/Administrative area. */ +@property(nonatomic, copy, readonly) NSString *administrativeArea; + +/** Postal/Zip code. */ +@property(nonatomic, copy, readonly) NSString *postalCode; + +/** The country name. */ +@property(nonatomic, copy, readonly) NSString *country; + +/** An array of NSString containing formatted lines of the address. May be nil. */ +@property(nonatomic, copy, readonly) NSArray *lines; + +/** + * Returns the first line of the address. + * + * This method is obsolete and deprecated and will be removed in a future release. + * Use the lines property instead. + */ +- (NSString *)addressLine1 __GMS_AVAILABLE_BUT_DEPRECATED; + +/** + * Returns the second line of the address. + * + * This method is obsolete and deprecated and will be removed in a future release. + * Use the lines property instead. + */ +- (NSString *)addressLine2 __GMS_AVAILABLE_BUT_DEPRECATED; + +@end + +/** + * The former type of geocode results (pre-1.7). This remains here for migration and will be + * removed in future releases. + */ +@compatibility_alias GMSReverseGeocodeResult GMSAddress; diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSAutocompleteFilter.h b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSAutocompleteFilter.h new file mode 100644 index 0000000..080ad00 --- /dev/null +++ b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSAutocompleteFilter.h @@ -0,0 +1,62 @@ +// +// GMSAutocompleteFilter.h +// Google Maps SDK for iOS +// +// Copyright 2014 Google Inc. +// +// Usage of this SDK is subject to the Google Maps/Google Earth APIs Terms of +// Service: https://developers.google.com/maps/terms +// + +/** + * The type filters that may be applied to an autocomplete request to restrict results to different + * types. + */ +typedef NS_ENUM(NSInteger, GMSPlacesAutocompleteTypeFilter) { + /** + * All results. + */ + kGMSPlacesAutocompleteTypeFilterNoFilter, + /** + * Geeocoding results, as opposed to business results. + */ + kGMSPlacesAutocompleteTypeFilterGeocode, + /** + * Geocoding results with a precise address. + */ + kGMSPlacesAutocompleteTypeFilterAddress, + /** + * Business results. + */ + kGMSPlacesAutocompleteTypeFilterEstablishment, + /** + * Results that match the following types: + * "locality", + * "sublocality" + * "postal_code", + * "country", + * "administrative_area_level_1", + * "administrative_area_level_2" + */ + kGMSPlacesAutocompleteTypeFilterRegion, + /** + * Results that match the following types: + * "locality", + * "administrative_area_level_3" + */ + kGMSPlacesAutocompleteTypeFilterCity, +}; + +/** + * This class represents a set of restrictions that may be applied to autocomplete requests. This + * allows customization of autocomplete suggestions to only those places that are of interest. + */ +@interface GMSAutocompleteFilter : NSObject + +/** + * The type filter applied to an autocomplete request to restrict results to different types. + * Default value is kGMSPlacesAutocompleteTypeFilterNoFilter. + */ +@property(nonatomic, assign) GMSPlacesAutocompleteTypeFilter type; + +@end diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSAutocompleteMatchFragment.h b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSAutocompleteMatchFragment.h new file mode 100644 index 0000000..5eb36cf --- /dev/null +++ b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSAutocompleteMatchFragment.h @@ -0,0 +1,29 @@ +// +// GMSAutocompleteMatchFragment.h +// Google Maps SDK for iOS +// +// Copyright 2014 Google Inc. +// +// Usage of this SDK is subject to the Google Maps/Google Earth APIs Terms of +// Service: https://developers.google.com/maps/terms +// + + +/** + * This class represents a matched fragment of a string. This is a contiguous range of characters + * in a string, suitable for highlighting in an autocompletion UI. + */ +@interface GMSAutocompleteMatchFragment : NSObject + +/** + * The offset of the matched fragment. This is an index into a string. The character at this index + * is the first matched character. + */ +@property(nonatomic, readonly) NSUInteger offset; + +/** + * The length of the matched fragment. + */ +@property(nonatomic, readonly) NSUInteger length; + +@end diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSAutocompletePrediction.h b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSAutocompletePrediction.h new file mode 100644 index 0000000..7ea0dbe --- /dev/null +++ b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSAutocompletePrediction.h @@ -0,0 +1,59 @@ +// +// GMSAutocompletePrediction.h +// Google Maps SDK for iOS +// +// Copyright 2014 Google Inc. +// +// Usage of this SDK is subject to the Google Maps/Google Earth APIs Terms of +// Service: https://developers.google.com/maps/terms +// + + +/* + * Attribute name for match fragments in |GMSAutocompletePrediction| attributedFullText. + */ +extern NSString *const kGMSAutocompleteMatchAttribute; + +/** + * This class represents a prediction of a full query based on a partially typed string. + */ +@interface GMSAutocompletePrediction : NSObject + +/** + * The full description of the prediction as a NSAttributedString. E.g., "Sydney Opera House, + * Sydney, New South Wales, Australia". + * + * Every text range that matches the user input has a |kGMSAutocompleteMatchAttribute|. For + * example, you can make every match bold using enumerateAttribute: + *
+ *   UIFont *regularFont = [UIFont systemFontOfSize:[UIFont labelFontSize]];
+ *   UIFont *boldFont = [UIFont boldSystemFontOfSize:[UIFont labelFontSize]];
+ *
+ *   NSMutableAttributedString *bolded = [prediction.attributedFullText mutableCopy];
+ *   [bolded enumerateAttribute:kGMSAutocompleteMatchAttribute
+ *                      inRange:NSMakeRange(0, bolded.length)
+ *                      options:0
+ *                   usingBlock:^(id value, NSRange range, BOOL *stop) {
+ *                     UIFont *font = (value == nil) ? regularFont : boldFont;
+ *                     [bolded addAttribute:NSFontAttributeName value:font range:range];
+ *                   }];
+ *
+ *   label.attributedText = bolded;
+ * 
+ */ +@property(nonatomic, copy, readonly) NSAttributedString *attributedFullText; + + +/** + * An optional property representing the place ID of the prediction, suitable for use in a place + * details request. + */ +@property(nonatomic, copy, readonly) NSString *placeID; + +/** + * The types of this autocomplete result. Types are NSStrings, valid values are any types + * documented at . + */ +@property(nonatomic, copy, readonly) NSArray *types; + +@end diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSCALayer.h b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSCALayer.h new file mode 100644 index 0000000..c10bc7b --- /dev/null +++ b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSCALayer.h @@ -0,0 +1,20 @@ +// +// GMSCALayer.h +// Google Maps SDK for iOS +// +// Copyright 2013 Google Inc. +// +// Usage of this SDK is subject to the Google Maps/Google Earth APIs Terms of +// Service: https://developers.google.com/maps/terms +// + +#import + +/** + * GMSCALayer is a superclass used by layers in the Google Maps SDK for iOS, + * such as GMSMapLayer and GMSPanoramaLayer. + * + * This is an implementation detail and it should not be instantiated directly. + */ +@interface GMSCALayer : CALayer +@end diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSCameraPosition.h b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSCameraPosition.h new file mode 100644 index 0000000..8ecdeae --- /dev/null +++ b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSCameraPosition.h @@ -0,0 +1,117 @@ +// +// GMSCameraPosition.h +// Google Maps SDK for iOS +// +// Copyright 2013 Google Inc. +// +// Usage of this SDK is subject to the Google Maps/Google Earth APIs Terms of +// Service: https://developers.google.com/maps/terms +// + +#import + +/** +* An immutable class that aggregates all camera position parameters. + */ +@interface GMSCameraPosition : NSObject + +/** + * Location on the Earth towards which the camera points. + */ +@property(nonatomic, readonly) CLLocationCoordinate2D target; + +/** + * Zoom level. Zoom uses an exponentional scale, where zoom 0 represents the entire world as a + * 256 x 256 square. Each successive zoom level increases magnification by a factor of 2. So at + * zoom level 1, the world is 512x512, and at zoom level 2, the entire world is 1024x1024. + */ +@property(nonatomic, readonly) float zoom; + +/** + * Bearing of the camera, in degrees clockwise from true north. + */ +@property(nonatomic, readonly) CLLocationDirection bearing; + +/** + * The angle, in degrees, of the camera angle from the nadir (directly facing the Earth). 0 is + * straight down, 90 is parallel to the ground. Note that the maximum angle allowed is 45 degrees. + */ +@property(nonatomic, readonly) double viewingAngle; + +/** + * Designated initializer. Configures this GMSCameraPosition with all available camera properties. + * Building a GMSCameraPosition via this initializer (or by the following convenience constructors) + * will implicitly clamp camera values. + * + * @param target location on the earth which the camera points + * @param zoom the zoom level near the center of the screen + * @param bearing of the camera in degrees from true north + * @param viewingAngle in degrees, of the camera angle from the nadir + */ +- (id)initWithTarget:(CLLocationCoordinate2D)target + zoom:(float)zoom + bearing:(CLLocationDirection)bearing + viewingAngle:(double)viewingAngle; + +/** + * Convenience constructor for GMSCameraPosition for a particular target and zoom level. This will + * set the bearing and viewingAngle properties of this camera to zero defaults (i.e., directly + * facing the Earth's surface, with the top of the screen pointing north). + */ ++ (instancetype)cameraWithTarget:(CLLocationCoordinate2D)target zoom:(float)zoom; + +/** + * Convenience constructor for GMSCameraPosition, as per cameraWithTarget:zoom:. + */ ++ (instancetype)cameraWithLatitude:(CLLocationDegrees)latitude + longitude:(CLLocationDegrees)longitude + zoom:(float)zoom; + +/** + * Convenience constructor for GMSCameraPosition, with all camera properties as per + * initWithTarget:zoom:bearing:viewingAngle:. + */ ++ (instancetype)cameraWithTarget:(CLLocationCoordinate2D)target + zoom:(float)zoom + bearing:(CLLocationDirection)bearing + viewingAngle:(double)viewingAngle; + +/** + * Convenience constructor for GMSCameraPosition, with latitude/longitude and all other camera + * properties as per initWithTarget:zoom:bearing:viewingAngle:. + */ ++ (instancetype)cameraWithLatitude:(CLLocationDegrees)latitude + longitude:(CLLocationDegrees)longitude + zoom:(float)zoom + bearing:(CLLocationDirection)bearing + viewingAngle:(double)viewingAngle; + +/** + * Get the zoom level at which |meters| distance, at given |coord| on Earth, correspond to the + * specified number of screen |points|. + * + * For extremely large or small distances the returned zoom level may be smaller or larger than the + * minimum or maximum zoom level allowed on the camera. + * + * This helper method is useful for building camera positions that contain specific physical areas + * on Earth. + */ ++ (float)zoomAtCoordinate:(CLLocationCoordinate2D)coordinate + forMeters:(CLLocationDistance)meters + perPoints:(CGFloat)points; + +@end + +/** Mutable version of GMSCameraPosition. */ +@interface GMSMutableCameraPosition : GMSCameraPosition +@property(nonatomic, assign) CLLocationCoordinate2D target; +@property(nonatomic, assign) float zoom; +@property(nonatomic, assign) CLLocationDirection bearing; +@property(nonatomic, assign) double viewingAngle; +@end + +/** The maximum zoom (closest to the Earth's surface) permitted by the map camera. */ +FOUNDATION_EXTERN const float kGMSMaxZoomLevel; + +/** The minimum zoom (farthest from the Earth's surface) permitted by the map camera. */ +FOUNDATION_EXTERN const float kGMSMinZoomLevel; diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSCameraUpdate.h b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSCameraUpdate.h new file mode 100644 index 0000000..7145ff1 --- /dev/null +++ b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSCameraUpdate.h @@ -0,0 +1,106 @@ +// +// GMSCameraUpdate.h +// Google Maps SDK for iOS +// +// Copyright 2013 Google Inc. +// +// Usage of this SDK is subject to the Google Maps/Google Earth APIs Terms of +// Service: https://developers.google.com/maps/terms +// + +#import +#import + +@class GMSCameraPosition; +@class GMSCoordinateBounds; + +/** + * GMSCameraUpdate represents an update that may be applied to a GMSMapView. + * It encapsulates some logic for modifying the current camera. + * It should only be constructed using the factory helper methods below. + */ +@interface GMSCameraUpdate : NSObject + +/** + * Returns a GMSCameraUpdate that zooms in on the map. + * The zoom increment is 1.0. + */ ++ (GMSCameraUpdate *)zoomIn; + +/** + * Returns a GMSCameraUpdate that zooms out on the map. + * The zoom increment is -1.0. + */ ++ (GMSCameraUpdate *)zoomOut; + +/** + * Returns a GMSCameraUpdate that changes the zoom by the specified amount. + */ ++ (GMSCameraUpdate *)zoomBy:(float)delta; + +/** + * Returns a GMSCameraUpdate that sets the zoom to the specified amount. + */ ++ (GMSCameraUpdate *)zoomTo:(float)zoom; + +/** + * Returns a GMSCameraUpdate that sets the camera target to the specified + * coordinate. + */ ++ (GMSCameraUpdate *)setTarget:(CLLocationCoordinate2D)target; + +/** + * Returns a GMSCameraUpdate that sets the camera target and zoom to the + * specified values. + */ ++ (GMSCameraUpdate *)setTarget:(CLLocationCoordinate2D)target zoom:(float)zoom; + +/** + * Returns a GMSCameraUpdate that sets the camera to the specified + * GMSCameraPosition. + */ ++ (GMSCameraUpdate *)setCamera:(GMSCameraPosition *)camera; + +/** + * Returns a GMSCameraUpdate that transforms the camera such that the specified + * bounds are centered on screen at the greatest possible zoom level. The bounds + * will have a default padding of 64 points. + * + * The returned camera update will set the camera's bearing and tilt to their + * default zero values (i.e., facing north and looking directly at the Earth). + */ ++ (GMSCameraUpdate *)fitBounds:(GMSCoordinateBounds *)bounds; + +/** + * This is similar to fitBounds: but allows specifying the padding (in points) + * in order to inset the bounding box from the view's edges. + * If the requested |padding| is larger than the view size in either the + * vertical or horizontal direction the map will be maximally zoomed out. + */ ++ (GMSCameraUpdate *)fitBounds:(GMSCoordinateBounds *)bounds + withPadding:(CGFloat)padding; + +/** + * This is similar to fitBounds: but allows specifying edge insets + * in order to inset the bounding box from the view's edges. + * If the requested |edgeInsets| are larger than the view size in either the + * vertical or horizontal direction the map will be maximally zoomed out. + */ ++ (GMSCameraUpdate *)fitBounds:(GMSCoordinateBounds *)bounds + withEdgeInsets:(UIEdgeInsets)edgeInsets; + +/** + * Returns a GMSCameraUpdate that shifts the center of the view by the + * specified number of points in the x and y directions. + * X grows to the right, Y grows down. + */ ++ (GMSCameraUpdate *)scrollByX:(CGFloat)dX Y:(CGFloat)dY; + +/** + * Returns a GMSCameraUpdate that zooms with a focus point; the focus point + * stays fixed on screen. + */ ++ (GMSCameraUpdate *)zoomBy:(float)zoom atPoint:(CGPoint)point; + +@end + diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSCircle.h b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSCircle.h new file mode 100644 index 0000000..b67e3bd --- /dev/null +++ b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSCircle.h @@ -0,0 +1,49 @@ +// +// GMSCircle.h +// Google Maps SDK for iOS +// +// Copyright 2013 Google Inc. +// +// Usage of this SDK is subject to the Google Maps/Google Earth APIs Terms of +// Service: https://developers.google.com/maps/terms +// + +#import + +#import + +/** + * A circle on the Earth's surface (spherical cap). + */ +@interface GMSCircle : GMSOverlay + +/** Position on Earth of circle center. */ +@property(nonatomic, assign) CLLocationCoordinate2D position; + +/** Radius of the circle in meters; must be positive. */ +@property(nonatomic, assign) CLLocationDistance radius; + +/** + * The width of the circle's outline in screen points. Defaults to 1. As per + * GMSPolygon, the width does not scale when the map is zoomed. + * Setting strokeWidth to 0 results in no stroke. + */ +@property(nonatomic, assign) CGFloat strokeWidth; + +/** The color of this circle's outline. The default value is black. */ +@property(nonatomic, strong) UIColor *strokeColor; + +/** + * The interior of the circle is painted with fillColor. + * The default value is nil, resulting in no fill. + */ +@property(nonatomic, strong) UIColor *fillColor; + +/** + * Convenience constructor for GMSCircle for a particular position and radius. + * Other properties will have default values. + */ ++ (instancetype)circleWithPosition:(CLLocationCoordinate2D)position + radius:(CLLocationDistance)radius; + +@end diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSCoordinateBounds.h b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSCoordinateBounds.h new file mode 100644 index 0000000..f7aae8a --- /dev/null +++ b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSCoordinateBounds.h @@ -0,0 +1,97 @@ +// +// GMSCoordinateBounds.h +// Google Maps SDK for iOS +// +// Copyright 2013 Google Inc. +// +// Usage of this SDK is subject to the Google Maps/Google Earth APIs Terms of +// Service: https://developers.google.com/maps/terms +// + +#import + +#import + +@class GMSPath; + +/** + * GMSCoordinateBounds represents a rectangular bounding box on the Earth's + * surface. GMSCoordinateBounds is immutable and can't be modified after + * construction. + */ +@interface GMSCoordinateBounds : NSObject + +/** The North-East corner of these bounds. */ +@property(nonatomic, readonly) CLLocationCoordinate2D northEast; + +/** The South-West corner of these bounds. */ +@property(nonatomic, readonly) CLLocationCoordinate2D southWest; + +/** + * Returns NO if this bounds does not contain any points. + * For example, [[GMSCoordinateBounds alloc] init].valid == NO. + * When an invalid bounds is expanded with valid coordinates via + * includingCoordinate: or includingBounds:, the resulting bounds will be valid + * but contain only the new coordinates. + */ +@property(readonly, getter=isValid) BOOL valid; + +/** + * Inits the northEast and southWest bounds corresponding + * to the rectangular region defined by the two corners. + * + * It is ambiguous whether the longitude of the box + * extends from |coord1| to |coord2| or vice-versa; + * the box is constructed as the smaller of the two variants, eliminating the + * ambiguity. + */ +- (id)initWithCoordinate:(CLLocationCoordinate2D)coord1 + coordinate:(CLLocationCoordinate2D)coord2; + +/** + * Inits with bounds that encompass |region|. + */ +- (id)initWithRegion:(GMSVisibleRegion)region; + +/** + * Inits with bounds that encompass |path|. + */ +- (id)initWithPath:(GMSPath *)path; + +/** + * Returns a GMSCoordinateBounds representing + * the current bounds extended to include the passed-in coordinate. + * If the current bounds is invalid, the result is a valid bounds containing + * only |coordinate|. + */ +- (GMSCoordinateBounds *)includingCoordinate:(CLLocationCoordinate2D)coordinate; + +/** + * Returns a GMSCoordinateBounds representing + * the current bounds extended to include the entire other bounds. + * If the current bounds is invalid, the result is a valid bounds equal + * to |other|. + */ +- (GMSCoordinateBounds *)includingBounds:(GMSCoordinateBounds *)other; + +/** + * Returns a GMSCoordinateBounds representing the current bounds extended to + * include |path|. + */ +- (GMSCoordinateBounds *)includingPath:(GMSPath *)path; + +/** + * Returns YES if |coordinate| is contained within this bounds. This includes + * points that lie exactly on the edge of the bounds. + */ +- (BOOL)containsCoordinate:(CLLocationCoordinate2D)coordinate; + +/** + * Returns YES if |other| overlaps with this bounds. + * Two bounds are overlapping if there is at least one coordinate point + * contained by both. + */ +- (BOOL)intersectsBounds:(GMSCoordinateBounds *)other; + +@end + diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSGeocoder.h b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSGeocoder.h new file mode 100644 index 0000000..6f3574b --- /dev/null +++ b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSGeocoder.h @@ -0,0 +1,56 @@ +// +// GMSGeocoder.h +// Google Maps SDK for iOS +// +// Copyright 2012 Google Inc. +// +// Usage of this SDK is subject to the Google Maps/Google Earth APIs Terms of +// Service: https://developers.google.com/maps/terms +// + +#import + +#import + +@class GMSReverseGeocodeResponse; + +/** GMSGeocoder error codes, embedded in NSError. */ +typedef NS_ENUM(NSInteger, GMSGeocoderErrorCode) { + kGMSGeocoderErrorInvalidCoordinate = 1, + kGMSGeocoderErrorInternal, +}; + +/** Handler that reports a reverse geocoding response, or error. */ +typedef void (^GMSReverseGeocodeCallback)(GMSReverseGeocodeResponse *, NSError *); + +/** + * Exposes a service for reverse geocoding. This maps Earth coordinates (latitude and longitude) to + * a collection of addresses near that coordinate. + */ +@interface GMSGeocoder : NSObject + +/* Convenience constructor for GMSGeocoder. */ ++ (GMSGeocoder *)geocoder; + +/** + * Reverse geocodes a coordinate on the Earth's surface. + * + * @param coordinate The coordinate to reverse geocode. + * @param handler The callback to invoke with the reverse geocode results. + * The callback will be invoked asynchronously from the main thread. + */ +- (void)reverseGeocodeCoordinate:(CLLocationCoordinate2D)coordinate + completionHandler:(GMSReverseGeocodeCallback)handler; + +@end + +/** A collection of results from a reverse geocode request. */ +@interface GMSReverseGeocodeResponse : NSObject + +/** Returns the first result, or nil if no results were available. */ +- (GMSAddress *)firstResult; + +/** Returns an array of all the results (contains GMSAddress), including the first result. */ +- (NSArray *)results; + +@end diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSGeometryUtils.h b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSGeometryUtils.h new file mode 100644 index 0000000..a50d6f6 --- /dev/null +++ b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSGeometryUtils.h @@ -0,0 +1,222 @@ +// +// GMSGeometryUtils.h +// Google Maps SDK for iOS +// +// Copyright 2013 Google Inc. +// +// Usage of this SDK is subject to the Google Maps/Google Earth APIs Terms of +// Service: https://developers.google.com/maps/terms +// + +/** + * \defgroup GeometryUtils GMSGeometryUtils + * @{ + */ + +#import + +#import + +@class GMSPath; + +/** Average Earth radius in meters. */ +static const CLLocationDistance kGMSEarthRadius = 6371009.0; + +/** + * A point on the map. May represent a projected coordinate. x is in [-1, 1]. + * The axis direction is normal: y grows towards North, x grows towards East. + * (0, 0) is the center of the map. See GMSProject() and GMSUnproject(). + */ +typedef struct GMSMapPoint { + double x; + double y; +} GMSMapPoint; + +/** Projects |coordinate| to the map. |coordinate| must be valid. */ +FOUNDATION_EXPORT +GMSMapPoint GMSProject(CLLocationCoordinate2D coordinate); + +/** Unprojects |point| from the map. point.x must be in [-1, 1]. */ +FOUNDATION_EXPORT +CLLocationCoordinate2D GMSUnproject(GMSMapPoint point); + +/** + * Returns a linearly interpolated point on the segment [a, b], at the fraction + * |t| from |a|. |t|==0 corresponds to |a|, |t|==1 corresponds to |b|. + * The interpolation takes place along the short path between the points + * potentially crossing the date line. E.g. interpolating from San Francisco + * to Tokyo will pass north of Hawaii and cross the date line. + */ +FOUNDATION_EXPORT +GMSMapPoint GMSMapPointInterpolate(GMSMapPoint a, GMSMapPoint b, double t); + +/** + * Returns the length of the segment [a, b] in projected space. The length is + * computed along the short path between the points potentially crossing the + * date line. E.g. the distance between the points corresponding to + * San Francisco and Tokyo measures the segment that passes north of Hawaii + * crossing the date line. + */ +FOUNDATION_EXPORT +double GMSMapPointDistance(GMSMapPoint a, GMSMapPoint b); + +/** + * Returns whether |point| lies inside of path. The path is always cosidered + * closed, regardless of whether the last point equals the first or not. + * Inside is defined as not containing the South Pole -- the South Pole is + * always outside. + * |path| describes great circle segments if |geodesic| is YES, and rhumb + * (loxodromic) segments otherwise. + * If |point| is exactly equal to one of the vertices, the result is YES. + * A point that is not equal to a vertex is on one side or the other of any path + * segment -- it can never be "exactly on the border". + * See GMSGeometryIsLocationOnPath() for a border test with tolerance. + */ +FOUNDATION_EXPORT +BOOL GMSGeometryContainsLocation(CLLocationCoordinate2D point, GMSPath *path, + BOOL geodesic); + +/** + * Returns whether |point| lies on or near |path|, within the specified + * |tolerance| in meters. + * |path| is composed of great circle segments if |geodesic| is YES, and of + * rhumb (loxodromic) segments if |geodesic| is NO. + * See also GMSGeometryIsLocationOnPath(point, path, geodesic). + * + * The tolerance, in meters, is relative to the spherical radius of the Earth. + * If you need to work on a sphere of different radius, + * you may compute the equivalent tolerance from the desired tolerance on the + * sphere of radius R: tolerance = toleranceR * (RadiusEarth / R), + * with RadiusEarth==6371009. + */ +FOUNDATION_EXPORT +BOOL GMSGeometryIsLocationOnPathTolerance(CLLocationCoordinate2D point, + GMSPath *path, + BOOL geodesic, + CLLocationDistance tolerance); + +/** + * Same as GMSGeometryIsLocationOnPath(point, path, geodesic, tolerance), + * with a default tolerance of 0.1 meters. + */ +FOUNDATION_EXPORT +BOOL GMSGeometryIsLocationOnPath(CLLocationCoordinate2D point, + GMSPath *path, + BOOL geodesic); + +/** + * Returns the great circle distance between two coordinates, in meters, + * on Earth. + * This is the shortest distance between the two coordinates on the sphere. + * Both coordinates must be valid. + */ +FOUNDATION_EXPORT +CLLocationDistance GMSGeometryDistance(CLLocationCoordinate2D from, + CLLocationCoordinate2D to); + +/** + * Returns the great circle length of |path|, in meters, on Earth. + * This is the sum of GMSGeometryDistance() over the path segments. + * All the coordinates of the path must be valid. + */ +FOUNDATION_EXPORT +CLLocationDistance GMSGeometryLength(GMSPath *path); + +/** + * Returns the area of a geodesic polygon defined by |path| on Earth. + * The "inside" of the polygon is defined as not containing the South pole. + * If |path| is not closed, it is implicitly treated as a closed path + * nevertheless and the result is the same. + * All coordinates of the path must be valid. + * If any segment of the path is a pair of antipodal points, the + * result is undefined -- because two antipodal points do not form a + * unique great circle segment on the sphere. + * The polygon must be simple (not self-overlapping) and may be concave. + */ +FOUNDATION_EXPORT +double GMSGeometryArea(GMSPath *path); + +/** + * Returns the signed area of a geodesic polygon defined by |path| on Earth. + * The result has the same absolute value as GMSGeometryArea(); it is positive + * if the points of path are in counter-clockwise order, and negative otherwise. + * The same restrictions as on GMSGeometryArea() apply. + */ +FOUNDATION_EXPORT +double GMSGeometrySignedArea(GMSPath *path); + +/** + * Returns the initial heading (degrees clockwise of North) at |from| + * of the shortest path to |to|. + * Returns 0 if the two coordinates are the same. + * Both coordinates must be valid. + * The returned value is in the range [0, 360). + * + * To get the final heading at |to| one may use + * (GMSGeometryHeading(|to|, |from|) + 180) modulo 360. + */ +FOUNDATION_EXPORT +CLLocationDirection GMSGeometryHeading(CLLocationCoordinate2D from, + CLLocationCoordinate2D to); + +/** + * Returns the destination coordinate, when starting at |from| + * with initial |heading|, travelling |distance| meters along a great circle + * arc, on Earth. + * The resulting longitude is in the range [-180, 180). + * Both coordinates must be valid. + */ +FOUNDATION_EXPORT +CLLocationCoordinate2D GMSGeometryOffset(CLLocationCoordinate2D from, + CLLocationDistance distance, + CLLocationDirection heading); + +/** + * Returns the coordinate that lies the given |fraction| of the way between + * the |from| and |to| coordinates on the shortest path between the two. + * The resulting longitude is in the range [-180, 180). + */ +FOUNDATION_EXPORT +CLLocationCoordinate2D GMSGeometryInterpolate(CLLocationCoordinate2D from, + CLLocationCoordinate2D to, + double fraction); + + +/** + * Returns an NSArray of GMSStyleSpan constructed by repeated application of style and length + * information from |styles| and |lengths| along |path|. + * + * |path| the path along which the output spans are computed. + * |styles| an NSArray of GMSStrokeStyle. Wraps if consumed. Can't be empty. + * |lengths| an NSArray of NSNumber; each entry gives the length of the corresponding + * style from |styles|. Wraps if consumed. Can't be empty. + * |lengthKind| the interpretation of values from |lengths| (geodesic, rhumb or projected). + * + * Example: a polyline with alternating black and white spans: + * + *
+ * GMSMutablePath *path;
+ * NSArray *styles = @[[GMSStrokeStyle solidColor:[UIColor whiteColor]],
+ *                     [GMSStrokeStyle solidColor:[UIColor blackColor]]];
+ * NSArray *lengths = @[@100000, @50000];
+ * polyline.path = path;
+ * polyline.spans = GMSStyleSpans(path, styles, lengths, kGMSLengthRhumb);
+ * 
+ */ +FOUNDATION_EXPORT +NSArray *GMSStyleSpans(GMSPath *path, NSArray *styles, NSArray *lengths, GMSLengthKind lengthKind); + +/** + * Similar to GMSStyleSpans(path, styles, lengths, lengthKind) but additionally takes an initial + * length offset that will be skipped over relative to the |lengths| array. + * + * |lengthOffset| the length (e.g. in meters) that should be skipped initially from |lengths|. + */ +FOUNDATION_EXPORT +NSArray *GMSStyleSpansOffset(GMSPath *path, + NSArray *styles, + NSArray *lengths, + GMSLengthKind lengthKind, + double lengthOffset); + +/**@}*/ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSGroundOverlay.h b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSGroundOverlay.h new file mode 100644 index 0000000..de88e0a --- /dev/null +++ b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSGroundOverlay.h @@ -0,0 +1,75 @@ +// +// GMSGroundOverlay.h +// Google Maps SDK for iOS +// +// Copyright 2013 Google Inc. +// +// Usage of this SDK is subject to the Google Maps/Google Earth APIs Terms of +// Service: https://developers.google.com/maps/terms +// + +#import + +@class GMSCoordinateBounds; + +/** + * GMSGroundOverlay specifies the available options for a ground overlay that + * exists on the Earth's surface. Unlike a marker, the position of a ground + * overlay is specified explicitly and it does not face the camera. + */ +@interface GMSGroundOverlay : GMSOverlay + +/** + * The position of this GMSGroundOverlay, or more specifically, the physical + * position of its anchor. If this is changed, |bounds| will be moved around + * the new position. + */ +@property(nonatomic, assign) CLLocationCoordinate2D position; + +/** + * The anchor specifies where this GMSGroundOverlay is anchored to the Earth in + * relation to |bounds|. If this is modified, |position| will be set to the + * corresponding new position within |bounds|. + */ +@property(nonatomic, assign) CGPoint anchor; + +/** + * Icon to render within |bounds| on the Earth. If this is nil, the overlay will + * not be visible (unlike GMSMarker which has a default image). + */ +@property(nonatomic, strong) UIImage *icon; + +/** + * Bearing of this ground overlay, in degrees. The default value, zero, points + * this ground overlay up/down along the normal Y axis of the earth. + */ +@property(nonatomic, assign) CLLocationDirection bearing; + +/** + * The 2D bounds on the Earth in which |icon| is drawn. Changing this value + * will adjust |position| accordingly. + */ +@property(nonatomic, strong) GMSCoordinateBounds *bounds; + +/** + * Convenience constructor for GMSGroundOverlay for a particular |bounds| and + * |icon|. Will set |position| accordingly. + */ ++ (instancetype)groundOverlayWithBounds:(GMSCoordinateBounds *)bounds + icon:(UIImage *)icon; + +/** + * Constructs a GMSGroundOverlay that renders the given |icon| at |position|, + * as if the image's actual size matches camera pixels at |zoomLevel|. + */ ++ (instancetype)groundOverlayWithPosition:(CLLocationCoordinate2D)position + icon:(UIImage *)icon + zoomLevel:(CGFloat)zoomLevel; + +@end + +/** + * The default position of the ground anchor of a GMSGroundOverlay: the center + * point of the icon. + */ +FOUNDATION_EXTERN const CGPoint kGMSGroundOverlayDefaultAnchor; diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSIndoorBuilding.h b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSIndoorBuilding.h new file mode 100644 index 0000000..c217483 --- /dev/null +++ b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSIndoorBuilding.h @@ -0,0 +1,35 @@ +// +// GMSIndoorBuilding.h +// Google Maps SDK for iOS +// +// Copyright 2013 Google Inc. +// +// Usage of this SDK is subject to the Google Maps/Google Earth APIs Terms of +// Service: https://developers.google.com/maps/terms +// + + +#import + +/** + * Describes a building which contains levels. + */ +@interface GMSIndoorBuilding : NSObject + +/** + * Array of GMSIndoorLevel describing the levels which make up the building. + * The levels are in 'display order' from top to bottom. + */ +@property(nonatomic, strong, readonly) NSArray *levels; + +/** + * Index in the levels array of the default level. + */ +@property(nonatomic, assign, readonly) NSUInteger defaultLevelIndex; + +/** + * If YES, the building is entirely underground and supports being hidden. + */ +@property(nonatomic, assign, readonly, getter=isUnderground) BOOL underground; + +@end diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSIndoorDisplay.h b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSIndoorDisplay.h new file mode 100644 index 0000000..0094cf4 --- /dev/null +++ b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSIndoorDisplay.h @@ -0,0 +1,61 @@ +// +// GMSIndoorDisplay.h +// Google Maps SDK for iOS +// +// Copyright 2013 Google Inc. +// +// Usage of this SDK is subject to the Google Maps/Google Earth APIs Terms of +// Service: https://developers.google.com/maps/terms +// + +#import + +@class GMSIndoorBuilding; +@class GMSIndoorLevel; + +/** Delegate for events on GMSIndoorDisplay. */ +@protocol GMSIndoorDisplayDelegate +@optional + +/** + * Raised when the activeBuilding has changed. The activeLevel will also have + * already been updated for the new building, but didChangeActiveLevel: will + * be raised after this method. + */ +- (void)didChangeActiveBuilding:(GMSIndoorBuilding *)building; + +/** + * Raised when the activeLevel has changed. This event is raised for all + * changes, including explicit setting of the property. + */ +- (void)didChangeActiveLevel:(GMSIndoorLevel *)level; + +@end + +/** + * Provides ability to observe or control the display of indoor level data. + * + * Like GMSMapView, GMSIndoorDisplay may only be used from the main thread. + */ +@interface GMSIndoorDisplay : NSObject + +/** GMSIndoorDisplay delegate */ +@property(nonatomic, weak) id delegate; + +/** + * Provides the currently focused building, will be nil if there is no + * building with indoor data currently under focus. + */ +@property(nonatomic, strong, readonly) GMSIndoorBuilding *activeBuilding; + +/** + * Provides and controls the active level for activeBuilding. Will be updated + * whenever activeBuilding changes, and may be set to any member of + * activeBuilding's levels property. May also be set to nil if the building is + * underground, to stop showing the building (the building will remain active). + * Will always be nil if activeBuilding is nil. + * Any attempt to set it to an invalid value will be ignored. + */ +@property(nonatomic, strong) GMSIndoorLevel *activeLevel; + +@end diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSIndoorLevel.h b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSIndoorLevel.h new file mode 100644 index 0000000..3fb3d21 --- /dev/null +++ b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSIndoorLevel.h @@ -0,0 +1,27 @@ +// +// GMSIndoorLevel.h +// Google Maps SDK for iOS +// +// Copyright 2013 Google Inc. +// +// Usage of this SDK is subject to the Google Maps/Google Earth APIs Terms of +// Service: https://developers.google.com/maps/terms +// + + +#import + +/** + * Describes a single level in a building. + * Multiple buildings can share a level - in this case the level instances will + * compare as equal, even though the level numbers/names may be different. + */ +@interface GMSIndoorLevel : NSObject + +/** Localized display name for the level, e.g. "Ground floor". */ +@property(nonatomic, copy, readonly) NSString *name; + +/** Localized short display name for the level, e.g. "1". */ +@property(nonatomic, copy, readonly) NSString *shortName; + +@end diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSMapLayer.h b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSMapLayer.h new file mode 100644 index 0000000..6c8388b --- /dev/null +++ b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSMapLayer.h @@ -0,0 +1,96 @@ +// +// GMSMapLayer.h +// Google Maps SDK for iOS +// +// Copyright 2013 Google Inc. +// +// Usage of this SDK is subject to the Google Maps/Google Earth APIs Terms of +// Service: https://developers.google.com/maps/terms +// + +#import +#import + +#import + +/** + * The following layer properties and constants describe the camera properties + * that may be animated on the custom model layer of a GMSMapView with Core + * Animation. For simple camera control and animation, please see the helper + * methods in GMSMapView+Animation.h, and the camera object definition within + * GMSCameraPosition.h. + * + * Changing layer properties triggers an implicit animation, e.g.:- + * mapView_.layer.cameraBearing = 20; + * + * An explicit animation, replacing the implicit animation, may be added after + * changing the property, e.g.- + * CAMediaTimingFunction *curve = [CAMediaTimingFunction functionWithName: + * kCAMediaTimingFunctionEaseInEaseOut]; + * CABasicAnimation *animation = + * [CABasicAnimation animationWithKeyPath:kGMSLayerCameraBearingKey]; + * animation.duration = 2.0f; + * animation.timingFunction = curve; + * animation.toValue = @20; + * [mapView_.layer addAnimation:animation forKey:kGMSLayerCameraBearingKey]; + * + * To control several implicit animations, Core Animation's transaction support + * may be used, e.g.- + * [CATransaction begin]; + * [CATransaction setAnimationDuration:2.0f]; + * mapView_.layer.cameraBearing = 20; + * mapView_.layer.cameraViewingAngle = 30; + * [CATransaction commit]; + * + * Note that these properties are not view-based. Please see "Animating View + * and Layer Changes Together" in the View Programming Guide for iOS- + * http://developer.apple.com/library/ios/#documentation/windowsviews/conceptual/viewpg_iphoneos/AnimatingViews/AnimatingViews.html + */ + +/** + * kGMSLayerCameraLatitudeKey ranges from [-85, 85], and values outside this + * range will be clamped. + */ +extern NSString *const kGMSLayerCameraLatitudeKey; + +/** + * kGMSLayerCameraLongitudeKey ranges from [-180, 180), and values outside this + * range will be wrapped to within this range. + */ +extern NSString *const kGMSLayerCameraLongitudeKey; + +/** + * kGMSLayerCameraBearingKey ranges from [0, 360), and values are wrapped. + */ +extern NSString *const kGMSLayerCameraBearingKey; + +/** + * kGMSLayerCameraZoomLevelKey ranges from [kGMSMinZoomLevel, kGMSMaxZoomLevel], + * and values are clamped. + */ +extern NSString *const kGMSLayerCameraZoomLevelKey; + +/** + * kGMSLayerCameraViewingAngleKey ranges from zero (i.e., facing straight down) + * and to between 30 and 45 degrees towards the horizon, depending on the model + * zoom level. + */ +extern NSString *const kGMSLayerCameraViewingAngleKey; + +/** + * GMSMapLayer is a custom subclass of CALayer, provided as the layer class on + * GMSMapView. This layer should not be instantiated directly. It provides + * model access to the camera normally defined on GMSMapView. + * + * Modifying or animating these properties will typically interrupt any current + * gesture on GMSMapView, e.g., a user's pan or rotation. Similarly, if a user + * performs an enabled gesture during an animation, the animation will stop + * 'in-place' (at the current presentation value). + */ +@interface GMSMapLayer : GMSCALayer +@property(nonatomic, assign) CLLocationDegrees cameraLatitude; +@property(nonatomic, assign) CLLocationDegrees cameraLongitude; +@property(nonatomic, assign) CLLocationDirection cameraBearing; +@property(nonatomic, assign) float cameraZoomLevel; +@property(nonatomic, assign) double cameraViewingAngle; +@end diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSMapView+Animation.h b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSMapView+Animation.h new file mode 100644 index 0000000..7dd2fef --- /dev/null +++ b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSMapView+Animation.h @@ -0,0 +1,57 @@ +// +// GMSMapView+Animation.h +// Google Maps SDK for iOS +// +// Copyright 2013 Google Inc. +// +// Usage of this SDK is subject to the Google Maps/Google Earth APIs Terms of +// Service: https://developers.google.com/maps/terms +// + +#import + +/** + * GMSMapView (Animation) offers several animation helper methods. + * + * During any animation, retrieving the camera position through the camera + * property on GMSMapView returns an intermediate immutable GMSCameraPosition. + * This camera position will typically represent the most recently drawn frame. + */ +@interface GMSMapView (Animation) + +/** Animates the camera of this map to |cameraPosition|. */ +- (void)animateToCameraPosition:(GMSCameraPosition *)cameraPosition; + +/** + * As animateToCameraPosition:, but changes only the location of the camera + * (i.e., from the current location to |location|). + */ +- (void)animateToLocation:(CLLocationCoordinate2D)location; + +/** + * As animateToCameraPosition:, but changes only the zoom level of the camera. + * This value is clamped by [kGMSMinZoomLevel, kGMSMaxZoomLevel]. + */ +- (void)animateToZoom:(float)zoom; + +/** + * As animateToCameraPosition:, but changes only the bearing of the camera (in + * degrees). Zero indicates true north. + */ +- (void)animateToBearing:(CLLocationDirection)bearing; + +/** + * As animateToCameraPosition:, but changes only the viewing angle of the camera + * (in degrees). This value will be clamped to a minimum of zero (i.e., facing + * straight down) and between 30 and 45 degrees towards the horizon, depending + * on the relative closeness to the earth. + */ +- (void)animateToViewingAngle:(double)viewingAngle; + +/** + * Applies |cameraUpdate| to the current camera, and then uses the result as + * per animateToCameraPosition:. + */ +- (void)animateWithCameraUpdate:(GMSCameraUpdate *)cameraUpdate; + +@end diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSMapView.h b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSMapView.h new file mode 100644 index 0000000..f58023e --- /dev/null +++ b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSMapView.h @@ -0,0 +1,378 @@ +// +// GMSMapView.h +// Google Maps SDK for iOS +// +// Copyright 2012 Google Inc. +// +// Usage of this SDK is subject to the Google Maps/Google Earth APIs Terms of +// Service: https://developers.google.com/maps/terms +// + +#import +#import + +#import +#import + +#ifndef __GMS_AVAILABLE_BUT_DEPRECATED +#define __GMS_AVAILABLE_BUT_DEPRECATED __deprecated +#endif + +@class GMSCameraPosition; +@class GMSCameraUpdate; +@class GMSCoordinateBounds; +@class GMSIndoorDisplay; +@class GMSMapLayer; +@class GMSMapView; +@class GMSMarker; +@class GMSOverlay; +@class GMSProjection; + +/** Delegate for events on GMSMapView. */ +@protocol GMSMapViewDelegate + +@optional + +/** + * Called before the camera on the map changes, either due to a gesture, + * animation (e.g., by a user tapping on the "My Location" button) or by being + * updated explicitly via the camera or a zero-length animation on layer. + * + * @param gesture If YES, this is occuring due to a user gesture. +*/ +- (void)mapView:(GMSMapView *)mapView willMove:(BOOL)gesture; + +/** + * Called repeatedly during any animations or gestures on the map (or once, if + * the camera is explicitly set). This may not be called for all intermediate + * camera positions. It is always called for the final position of an animation + * or gesture. + */ +- (void)mapView:(GMSMapView *)mapView + didChangeCameraPosition:(GMSCameraPosition *)position; + +/** + * Called when the map becomes idle, after any outstanding gestures or + * animations have completed (or after the camera has been explicitly set). + */ +- (void)mapView:(GMSMapView *)mapView + idleAtCameraPosition:(GMSCameraPosition *)position; + +/** + * Called after a tap gesture at a particular coordinate, but only if a marker + * was not tapped. This is called before deselecting any currently selected + * marker (the implicit action for tapping on the map). + */ +- (void)mapView:(GMSMapView *)mapView + didTapAtCoordinate:(CLLocationCoordinate2D)coordinate; + +/** + * Called after a long-press gesture at a particular coordinate. + * + * @param mapView The map view that was pressed. + * @param coordinate The location that was pressed. + */ +- (void)mapView:(GMSMapView *)mapView + didLongPressAtCoordinate:(CLLocationCoordinate2D)coordinate; + +/** + * Called after a marker has been tapped. + * + * @param mapView The map view that was pressed. + * @param marker The marker that was pressed. + * @return YES if this delegate handled the tap event, which prevents the map + * from performing its default selection behavior, and NO if the map + * should continue with its default selection behavior. + */ +- (BOOL)mapView:(GMSMapView *)mapView didTapMarker:(GMSMarker *)marker; + +/** + * Called after a marker's info window has been tapped. + */ +- (void)mapView:(GMSMapView *)mapView + didTapInfoWindowOfMarker:(GMSMarker *)marker; + +/** + * Called after an overlay has been tapped. + * This method is not called for taps on markers. + * + * @param mapView The map view that was pressed. + * @param overlay The overlay that was pressed. + */ +- (void)mapView:(GMSMapView *)mapView didTapOverlay:(GMSOverlay *)overlay; + +/** + * Called when a marker is about to become selected, and provides an optional + * custom info window to use for that marker if this method returns a UIView. + * If you change this view after this method is called, those changes will not + * necessarily be reflected in the rendered version. + * + * The returned UIView must not have bounds greater than 500 points on either + * dimension. As there is only one info window shown at any time, the returned + * view may be reused between other info windows. + * + * Removing the marker from the map or changing the map's selected marker during + * this call results in undefined behavior. + * + * @return The custom info window for the specified marker, or nil for default + */ +- (UIView *)mapView:(GMSMapView *)mapView markerInfoWindow:(GMSMarker *)marker; + +/** + * Called when mapView:markerInfoWindow: returns nil. If this method returns a + * view, it will be placed within the default info window frame. If this method + * returns nil, then the default rendering will be used instead. + * + * @param mapView The map view that was pressed. + * @param marker The marker that was pressed. + * @return The custom view to disaply as contents in the info window, or null to + * use the default content rendering instead + */ + +- (UIView *)mapView:(GMSMapView *)mapView markerInfoContents:(GMSMarker *)marker; + +/** + * Called when dragging has been initiated on a marker. + */ +- (void)mapView:(GMSMapView *)mapView didBeginDraggingMarker:(GMSMarker *)marker; + +/** + * Called after dragging of a marker ended. + */ +- (void)mapView:(GMSMapView *)mapView didEndDraggingMarker:(GMSMarker *)marker; + +/** + * Called while a marker is dragged. + */ +- (void)mapView:(GMSMapView *)mapView didDragMarker:(GMSMarker *)marker; + +/** + * Called when the My Location button is tapped. + * + * @return YES if the listener has consumed the event (i.e., the default behavior should not occur), + * NO otherwise (i.e., the default behavior should occur). The default behavior is for the + * camera to move such that it is centered on the user location. + */ +- (BOOL)didTapMyLocationButtonForMapView:(GMSMapView *)mapView; + +@end + +/** + * Display types for GMSMapView. + */ +typedef enum { + /** Basic maps. The default. */ + kGMSTypeNormal = 1, + + /** Satellite maps with no labels. */ + kGMSTypeSatellite, + + /** Terrain maps. */ + kGMSTypeTerrain, + + /** Satellite maps with a transparent label overview. */ + kGMSTypeHybrid, + + /** No maps, no labels. Display of traffic data is not supported. */ + kGMSTypeNone, + +} GMSMapViewType; + +/** + * This is the main class of the Google Maps SDK for iOS and is the entry point + * for all methods related to the map. + * + * The map should be instantiated via the convenience constructor + * [GMSMapView mapWithFrame:camera:]. It may also be created with the default + * [[GMSMapView alloc] initWithFrame:] method (wherein its camera will be set to + * a default location). + * + * GMSMapView can only be read and modified from the main thread, similar to all + * UIKit objects. Calling these methods from another thread will result in an + * exception or undefined behavior. + */ +@interface GMSMapView : UIView + +/** GMSMapView delegate. */ +@property(nonatomic, weak) IBOutlet id delegate; + +/** + * Controls the camera, which defines how the map is oriented. Modification of + * this property is instantaneous. + */ +@property(nonatomic, copy) GMSCameraPosition *camera; + +/** + * Returns a GMSProjection object that you can use to convert between screen + * coordinates and latitude/longitude coordinates. + * + * This is a snapshot of the current projection, and will not automatically + * update when the camera moves. It represents either the projection of the last + * drawn GMSMapView frame, or; where the camera has been explicitly set or the + * map just created, the upcoming frame. It will never be nil. + */ +@property(nonatomic, readonly) GMSProjection *projection; + +/** + * Controls whether the My Location dot and accuracy circle is enabled. + * Defaults to NO. + */ +@property(nonatomic, assign, getter=isMyLocationEnabled) BOOL myLocationEnabled; + +/** + * If My Location is enabled, reveals where the user location dot is being + * drawn. If it is disabled, or it is enabled but no location data is available, + * this will be nil. This property is observable using KVO. + */ +@property(nonatomic, strong, readonly) CLLocation *myLocation; + +/** + * The marker that is selected. Setting this property selects a particular + * marker, showing an info window on it. If this property is non-nil, setting + * it to nil deselects the marker, hiding the info window. This property is + * observable using KVO. + */ +@property(nonatomic, strong) GMSMarker *selectedMarker; + +/** + * Controls whether the map is drawing traffic data, if available. This is + * subject to the availability of traffic data. Defaults to NO. + */ +@property(nonatomic, assign, getter=isTrafficEnabled) BOOL trafficEnabled; + +/** + * Controls the type of map tiles that should be displayed. Defaults to + * kGMSTypeNormal. + */ +@property(nonatomic, assign) GMSMapViewType mapType; + +/** + * Minimum zoom (the farthest the camera may be zoomed out). Defaults to + * kGMSMinZoomLevel. Modified with -setMinZoom:maxZoom:. + */ +@property(nonatomic, assign, readonly) float minZoom; + +/** + * Maximum zoom (the closest the camera may be to the Earth). Defaults to + * kGMSMaxZoomLevel. Modified with -setMinZoom:maxZoom:. + */ +@property(nonatomic, assign, readonly) float maxZoom; + +/** + * If set, 3D buildings will be shown where available. Defaults to YES. + * + * This may be useful when adding a custom tile layer to the map, in order to + * make it clearer at high zoom levels. Changing this value will cause all + * tiles to be briefly invalidated. + */ +@property(nonatomic, assign, getter=isBuildingsEnabled) BOOL buildingsEnabled; + +/** + * Sets whether indoor maps are shown, where available. Defaults to YES. + * + * If this is set to NO, caches for indoor data may be purged and any floor + * currently selected by the end-user may be reset. + */ +@property(nonatomic, assign, getter=isIndoorEnabled) BOOL indoorEnabled; + +/** + * Gets the GMSIndoorDisplay instance which allows to observe or control + * aspects of indoor data display. + */ +@property(nonatomic, strong, readonly) GMSIndoorDisplay *indoorDisplay; + +/** + * Gets the GMSUISettings object, which controls user interface settings for the + * map. + */ +@property(nonatomic, strong, readonly) GMSUISettings *settings; + +/** + * Controls the 'visible' region of the view. By applying padding an area + * arround the edge of the view can be created which will contain map data + * but will not contain UI controls. + * + * If the padding is not balanced, the visual center of the view will move as + * appropriate. Padding will also affect the |projection| property so the + * visible region will not include the padding area. GMSCameraUpdate + * fitToBounds will ensure that both this padding and any padding requested + * will be taken into account. + * + * This property may be animated within a UIView-based animation block. + */ +@property(nonatomic, assign) UIEdgeInsets padding; + +/** + * Defaults to YES. If set to NO, GMSMapView will generate accessibility + * elements for overlay objects, such as GMSMarker and GMSPolyline. + * + * This property is as per the informal UIAcessibility protocol, except for the + * default value of YES. + */ +@property(nonatomic) BOOL accessibilityElementsHidden; + +/** + * Accessor for the custom CALayer type used for the layer. + */ +@property(nonatomic, readonly, retain) GMSMapLayer *layer; + +/** + * Builds and returns a GMSMapView, with a frame and camera target. + */ ++ (instancetype)mapWithFrame:(CGRect)frame camera:(GMSCameraPosition *)camera; + +/** + * Tells this map to power up its renderer. This is optional and idempotent. + * + * This method is obsolete and deprecated and will be removed in a future release. + */ +- (void)startRendering __GMS_AVAILABLE_BUT_DEPRECATED; + +/** + * Tells this map to power down its renderer. This is optional and idempotent. + * + * This method is obsolete and deprecated and will be removed in a future release. + */ +- (void)stopRendering __GMS_AVAILABLE_BUT_DEPRECATED; + +/** + * Clears all markup that has been added to the map, including markers, + * polylines and ground overlays. This will not clear the visible location dot + * or reset the current mapType. + */ +- (void)clear; + +/** + * Sets |minZoom| and |maxZoom|. This method expects the minimum to be less than + * or equal to the maximum, and will throw an exception with name + * NSRangeException otherwise. + */ +- (void)setMinZoom:(float)minZoom maxZoom:(float)maxZoom; + +/** + * Build a GMSCameraPosition that presents |bounds| with |padding|. The camera + * will have a zero bearing and tilt (i.e., facing north and looking directly at + * the Earth). This takes the frame and padding of this GMSMapView into account. + * + * If the bounds is nil or invalid this method will return a nil camera. + */ +- (GMSCameraPosition *)cameraForBounds:(GMSCoordinateBounds *)bounds + insets:(UIEdgeInsets)insets; + +/** + * Changes the camera according to |update|. + * The camera change is instantaneous (with no animation). + */ +- (void)moveCamera:(GMSCameraUpdate *)update; + +@end + +/** + * Accessibility identifier for the compass button. + */ +extern NSString *const kGMSAccessibilityCompass; + +/** + * Accessibility identifier for the "my location" button. + */ +extern NSString *const kGMSAccessibilityMyLocation; diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSMarker.h b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSMarker.h new file mode 100644 index 0000000..aaf0f99 --- /dev/null +++ b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSMarker.h @@ -0,0 +1,151 @@ +// +// GMSMarker.h +// Google Maps SDK for iOS +// +// Copyright 2012 Google Inc. +// +// Usage of this SDK is subject to the Google Maps/Google Earth APIs Terms of +// Service: https://developers.google.com/maps/terms +// + +#import + +@class GMSMarkerLayer; +@class GMSPanoramaView; +@class UIImage; + +/** + * Animation types for GMSMarker. + */ +typedef enum { + /** No animation (default). */ + kGMSMarkerAnimationNone = 0, + + /** The marker will pop from its groundAnchor when added. */ + kGMSMarkerAnimationPop, +} GMSMarkerAnimation; + +/** + * A marker is an icon placed at a particular point on the map's surface. A + * marker's icon is drawn oriented against the device's screen rather than the + * map's surface; i.e., it will not necessarily change orientation due to map + * rotations, tilting, or zooming. + */ +@interface GMSMarker : GMSOverlay + +/** Marker position. Animated. */ +@property(nonatomic, assign) CLLocationCoordinate2D position; + +/** Snippet text, shown beneath the title in the info window when selected. */ +@property(nonatomic, copy) NSString *snippet; + +/** + * Marker icon to render. If left nil, uses a default SDK place marker. + * + * Supports animated images, but each frame must be the same size or the + * behavior is undefined. + * + * Supports the use of alignmentRectInsets to specify a reduced tap area. This + * also redefines how anchors are specified. For an animated image the + * value for the animation is used, not the individual frames. + */ +@property(nonatomic, strong) UIImage *icon; + +/** + * The ground anchor specifies the point in the icon image that is anchored to + * the marker's position on the Earth's surface. This point is specified within + * the continuous space [0.0, 1.0] x [0.0, 1.0], where (0,0) is the top-left + * corner of the image, and (1,1) is the bottom-right corner. + * + * If the image has non-zero alignmentRectInsets, the top-left and bottom-right + * mentioned above refer to the inset section of the image. + */ +@property(nonatomic, assign) CGPoint groundAnchor; + +/** + * The info window anchor specifies the point in the icon image at which to + * anchor the info window, which will be displayed directly above this point. + * This point is specified within the same space as groundAnchor. + */ +@property(nonatomic, assign) CGPoint infoWindowAnchor; + +/** + * Controls the animation used when this marker is placed on a GMSMapView + * (default kGMSMarkerAnimationNone, no animation). + */ +@property(nonatomic, assign) GMSMarkerAnimation appearAnimation; + +/** + * Controls whether this marker can be dragged interactively (default NO). + */ +@property(nonatomic, assign, getter=isDraggable) BOOL draggable; + +/** + * Controls whether this marker should be flat against the Earth's surface (YES) + * or a billboard facing the camera (NO, default). + */ +@property(nonatomic, assign, getter=isFlat) BOOL flat; + +/** + * Sets the rotation of the marker in degrees clockwise about the marker's + * anchor point. The axis of rotation is perpendicular to the marker. A rotation + * of 0 corresponds to the default position of the marker. Animated. + * + * When the marker is flat on the map, the default position is north aligned and + * the rotation is such that the marker always remains flat on the map. When the + * marker is a billboard, the default position is pointing up and the rotation + * is such that the marker is always facing the camera. + */ +@property(nonatomic, assign) CLLocationDegrees rotation; + +/** + * Sets the opacity of the marker, between 0 (completely transparent) and 1 + * (default) inclusive. + */ +@property(nonatomic, assign) float opacity; + +/** + * Marker data. You can use this property to associate an arbitrary object with + * this marker. Google Maps SDK for iOS neither reads nor writes this property. + * + * Note that userData should not hold any strong references to any Maps + * objects, otherwise a loop may be created (preventing ARC from releasing + * objects). + */ +@property(nonatomic, strong) id userData; + +/** + * Provides the Core Animation layer for this GMSMarker. + */ +@property(nonatomic, strong, readonly) GMSMarkerLayer *layer; + +/** + * The |panoramaView| specifies which panorama view will attempt to show this + * marker. Note that if the marker's |position| is too far away from the + * |panoramaView|'s current panorama location, it will not be displayed as it + * will be too small. + * Can be set to nil to remove the marker from any current panorama view it + * is attached to. + * A marker can be shown on both a panorama and a map at the same time. + */ +@property(nonatomic, weak) GMSPanoramaView *panoramaView; + +/** Convenience constructor for a default marker. */ ++ (instancetype)markerWithPosition:(CLLocationCoordinate2D)position; + +/** Creates a tinted version of the default marker image for use as an icon. */ ++ (UIImage *)markerImageWithColor:(UIColor *)color; + +@end + +/** + * The default position of the ground anchor of a GMSMarker: the center bottom + * point of the marker icon. + */ +FOUNDATION_EXTERN const CGPoint kGMSMarkerDefaultGroundAnchor; + +/** + * The default position of the info window anchor of a GMSMarker: the center top + * point of the marker icon. + */ +FOUNDATION_EXTERN const CGPoint kGMSMarkerDefaultInfoWindowAnchor; diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSMarkerLayer.h b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSMarkerLayer.h new file mode 100644 index 0000000..91347b2 --- /dev/null +++ b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSMarkerLayer.h @@ -0,0 +1,42 @@ +// +// GMSMarkerLayer.h +// Google Maps SDK for iOS +// +// Copyright 2013 Google Inc. +// +// Usage of this SDK is subject to the Google Maps/Google Earth APIs Terms of +// Service: https://developers.google.com/maps/terms +// + +#import +#import + +/** + * GMSMarkerLayer is a custom subclass of CALayer, available on a per-marker + * basis, that allows animation of several properties of its associated + * GMSMarker. + * + * Note that this CALayer is never actually rendered directly, as GMSMapView is + * provided entirely via an OpenGL layer. As such, adjustments or animations to + * 'default' properties of CALayer will not have any effect. + */ +@interface GMSMarkerLayer : CALayer + +/** Latitude, part of |position| on GMSMarker. */ +@property(nonatomic, assign) CLLocationDegrees latitude; + +/** Longitude, part of |position| on GMSMarker. */ +@property(nonatomic, assign) CLLocationDegrees longitude; + +/** Rotation, as per GMSMarker. */ +@property(nonatomic, assign) CLLocationDegrees rotation; + +/** Opacity, as per GMSMarker. */ +@property float opacity; + +@end + +extern NSString *const kGMSMarkerLayerLatitude; +extern NSString *const kGMSMarkerLayerLongitude; +extern NSString *const kGMSMarkerLayerRotation; +extern NSString *const kGMSMarkerLayerOpacity; diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSMutablePath.h b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSMutablePath.h new file mode 100644 index 0000000..4f0100c --- /dev/null +++ b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSMutablePath.h @@ -0,0 +1,61 @@ +// +// GMSMutablePath.h +// Google Maps SDK for iOS +// +// Copyright 2013 Google Inc. +// +// Usage of this SDK is subject to the Google Maps/Google Earth APIs Terms of +// Service: https://developers.google.com/maps/terms +// + +#import + +#import +#import + +/** + * GMSMutablePath is a dynamic (resizable) array of CLLocationCoordinate2D. All coordinates must be + * valid. GMSMutablePath is the mutable counterpart to the immutable GMSPath. + */ +@interface GMSMutablePath : GMSPath + +/** Adds |coord| at the end of the path. */ +- (void)addCoordinate:(CLLocationCoordinate2D)coord; + +/** Adds a new CLLocationCoordinate2D instance with the given lat/lng. */ +- (void)addLatitude:(CLLocationDegrees)latitude longitude:(CLLocationDegrees)longitude; + +/** + * Inserts |coord| at |index|. + * + * If this is smaller than the size of the path, shifts all coordinates forward by one. Otherwise, + * behaves as replaceCoordinateAtIndex:withCoordinate:. + */ +- (void)insertCoordinate:(CLLocationCoordinate2D)coord atIndex:(NSUInteger)index; + +/** + * Replace the coordinate at |index| with |coord|. If |index| is after the end, grows the array with + * an undefined coordinate. + */ +- (void)replaceCoordinateAtIndex:(NSUInteger)index + withCoordinate:(CLLocationCoordinate2D)coord; + +/** + * Remove entry at |index|. + * + * If |index| < count decrements size. If |index| >= count this is a silent + * no-op. + */ +- (void)removeCoordinateAtIndex:(NSUInteger)index; + +/** + * Removes the last coordinate of the path. + * + * If the array is non-empty decrements size. If the array is empty, this is a silent no-op. + */ +- (void)removeLastCoordinate; + +/** Removes all coordinates in this path. */ +- (void)removeAllCoordinates; + +@end diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSOrientation.h b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSOrientation.h new file mode 100644 index 0000000..9a975c4 --- /dev/null +++ b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSOrientation.h @@ -0,0 +1,40 @@ +// +// GMSOrientation.h +// Google Maps SDK for iOS +// +// Copyright 2013 Google Inc. +// +// Usage of this SDK is subject to the Google Maps/Google Earth APIs Terms of +// Service: https://developers.google.com/maps/terms +// + +#import + +/** + * GMSOrientation is a tuple of heading and pitch used to control the viewing direction of a + * GMSPanoramaCamera. + */ +typedef struct { + /** The camera heading (horizontal angle) in degrees. */ + const CLLocationDirection heading; + + /** + * The camera pitch (vertical angle), in degrees from the horizon. The |pitch| range is [-90,90], + * although it is possible that not the full range is supported. + */ + const double pitch; +} GMSOrientation; + +#ifdef __cplusplus +extern "C" { +#endif + +/** Returns a GMSOrientation with the given |heading| and |pitch|. */ +inline GMSOrientation GMSOrientationMake(CLLocationDirection heading, double pitch) { + GMSOrientation orientation = {heading, pitch}; + return orientation; +} + +#ifdef __cplusplus +} +#endif diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSOverlay.h b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSOverlay.h new file mode 100644 index 0000000..a404868 --- /dev/null +++ b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSOverlay.h @@ -0,0 +1,56 @@ +// +// GMSOverlay.h +// Google Maps SDK for iOS +// +// Copyright 2013 Google Inc. +// +// Usage of this SDK is subject to the Google Maps/Google Earth APIs Terms of +// Service: https://developers.google.com/maps/terms +// + +#import + +@class GMSMapView; + +/** + * GMSOverlay is an abstract class that represents some overlay that may be + * attached to a specific GMSMapView. It may not be instantiated directly; + * instead, instances of concrete overlay types should be created directly + * (such as GMSMarker, GMSPolyline, and GMSPolygon). + * + * This supports the NSCopying protocol; [overlay_ copy] will return a copy + * of the overlay type, but with |map| set to nil. + */ +@interface GMSOverlay : NSObject + +/** + * Title, a short description of the overlay. Some overlays, such as markers, + * will display the title on the map. The title is also the default + * accessibility text. + */ +@property(nonatomic, copy) NSString *title; + +/** + * The map this overlay is on. Setting this property will add the overlay to the + * map. Setting it to nil removes this overlay from the map. An overlay may be + * active on at most one map at any given time. + */ +@property(nonatomic, weak) GMSMapView *map; + +/** + * If this overlay should cause tap notifications. Some overlays, such as + * markers, will default to being tappable. + */ +@property(nonatomic, assign, getter=isTappable) BOOL tappable; + +/** + * Higher |zIndex| value overlays will be drawn on top of lower |zIndex| + * value tile layers and overlays. Equal values result in undefined draw + * ordering. Markers are an exception that regardless of |zIndex|, they will + * always be drawn above tile layers and other non-marker overlays; they + * are effectively considered to be in a separate z-index group compared to + * other overlays. + */ +@property(nonatomic, assign) int zIndex; + +@end diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSPanorama.h b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSPanorama.h new file mode 100644 index 0000000..25a4e90 --- /dev/null +++ b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSPanorama.h @@ -0,0 +1,28 @@ +// +// GMSPanorama.h +// Google Maps SDK for iOS +// +// Copyright 2013 Google Inc. +// +// Usage of this SDK is subject to the Google Maps/Google Earth APIs Terms of +// Service: https://developers.google.com/maps/terms +// + +#import + +/** + * GMSPanorama represents metadata for a specific panorama on the Earth. This class is not + * instantiable directly and is obtained via GMSPanoramaService or GMSPanoramaView. + */ +@interface GMSPanorama : NSObject + +/** The precise location of this panorama. */ +@property(nonatomic, readonly) CLLocationCoordinate2D coordinate; + +/** The ID of this panorama. Panoramas may change ID over time, so this should not be persisted */ +@property(nonatomic, copy, readonly) NSString *panoramaID; + +/** An array of GMSPanoramaLink describing the neighboring panoramas. */ +@property(nonatomic, copy, readonly) NSArray *links; + +@end diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSPanoramaCamera.h b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSPanoramaCamera.h new file mode 100644 index 0000000..bf02be4 --- /dev/null +++ b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSPanoramaCamera.h @@ -0,0 +1,77 @@ +// +// GMSPanoramaCamera.h +// Google Maps SDK for iOS +// +// Copyright 2013 Google Inc. +// +// Usage of this SDK is subject to the Google Maps/Google Earth APIs Terms of +// Service: https://developers.google.com/maps/terms +// + +#import + +#import + +/** + * GMSPanoramaCamera is used to control the viewing direction of a GMSPanoramaView. It does not + * contain information about which particular panorama should be displayed. + */ +@interface GMSPanoramaCamera : NSObject + +/** + * Designated initializer. Configures this GMSPanoramaCamera with |orientation|, |zoom| and |FOV|. + * These values will be clamped to acceptable ranges. + */ +- (id)initWithOrientation:(GMSOrientation)orientation zoom:(float)zoom FOV:(double)FOV; + +/** + * Convenience constructor specifying heading and pitch as part of |orientation|, plus |zoom| and + * default field of view (90 degrees). + */ ++ (instancetype)cameraWithOrientation:(GMSOrientation)orientation zoom:(float)zoom; + +/** + * Convenience constructor specifying |heading|, |pitch|, |zoom| with default field of view (90 + * degrees). + */ ++ (instancetype)cameraWithHeading:(CLLocationDirection)heading pitch:(double)pitch zoom:(float)zoom; + +/** + * Convenience constructor for GMSPanoramaCamera, specifying all camera properties with heading and + * pitch as part of |orientation|. + */ ++ (instancetype)cameraWithOrientation:(GMSOrientation)orientation zoom:(float)zoom FOV:(double)FOV; + +/** + * Convenience constructor for GMSPanoramaCamera, specifying all camera properties. + */ ++ (instancetype)cameraWithHeading:(CLLocationDirection)heading + pitch:(double)pitch + zoom:(float)zoom + FOV:(double)FOV; + +/** + * The field of view (FOV) encompassed by the larger dimension (width or height) of the view in + * degrees at zoom 1. This is clamped to the range [1, 160] degrees, and has a default value of 90. + * + * Lower FOV values produce a zooming in effect; larger FOV values produce an fisheye effect. + * + * Note: This is not the displayed FOV if zoom is anything other than 1. User zoom gestures + * control the zoom property, not this property. + */ +@property(nonatomic, assign, readonly) double FOV; + +/** + * Adjusts the visible region of the screen. A zoom of N will show the same area as the central + * width/N height/N area of what is shown at zoom 1. + * + * Zoom is clamped to the implementation defined range [1, 5]. + */ +@property(nonatomic, assign, readonly) float zoom; + +/** + * The camera orientation, which groups together heading and pitch. + */ +@property(nonatomic, assign, readonly) GMSOrientation orientation; + +@end diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSPanoramaCameraUpdate.h b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSPanoramaCameraUpdate.h new file mode 100644 index 0000000..e97aabd --- /dev/null +++ b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSPanoramaCameraUpdate.h @@ -0,0 +1,25 @@ +// +// GMSPanoramaCameraUpdate.h +// Google Maps SDK for iOS +// +// Copyright 2013 Google Inc. +// +// Usage of this SDK is subject to the Google Maps/Google Earth APIs Terms of +// Service: https://developers.google.com/maps/terms +// + +@interface GMSPanoramaCameraUpdate : NSObject + +/** Returns an update that increments the camera heading with |deltaHeading|. */ ++ (GMSPanoramaCameraUpdate *)rotateBy:(CGFloat)deltaHeading; + +/** Returns an update that sets the camera heading to the given value. */ ++ (GMSPanoramaCameraUpdate *)setHeading:(CGFloat)heading; + +/** Returns an update that sets the camera pitch to the given value. */ ++ (GMSPanoramaCameraUpdate *)setPitch:(CGFloat)pitch; + +/** Returns an update that sets the camera zoom to the given value. */ ++ (GMSPanoramaCameraUpdate *)setZoom:(CGFloat)zoom; + +@end diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSPanoramaLayer.h b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSPanoramaLayer.h new file mode 100644 index 0000000..7dd0524 --- /dev/null +++ b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSPanoramaLayer.h @@ -0,0 +1,37 @@ +// +// GMSPanoramaLayer.h +// Google Maps SDK for iOS +// +// Copyright 2013 Google Inc. +// +// Usage of this SDK is subject to the Google Maps/Google Earth APIs Terms of +// Service: https://developers.google.com/maps/terms +// + +#import +#import + +#import + +/** kGMSLayerPanoramaHeadingKey ranges from [0, 360). */ +extern NSString *const kGMSLayerPanoramaHeadingKey; + +/** kGMSLayerPanoramaPitchKey ranges from [-90, 90]. */ +extern NSString *const kGMSLayerPanoramaPitchKey; + +/** kGMSLayerCameraZoomLevelKey ranges from [1, 5], default 1. */ +extern NSString *const kGMSLayerPanoramaZoomKey; + +/** kGMSLayerPanoramaFOVKey ranges from [1, 160] (in degrees), default 90. */ +extern NSString *const kGMSLayerPanoramaFOVKey; + +/** + * GMSPanoramaLayer is a custom subclass of CALayer, provided as the layer + * class on GMSPanoramaView. This layer should not be instantiated directly. + */ +@interface GMSPanoramaLayer : GMSCALayer +@property(nonatomic, assign) CLLocationDirection cameraHeading; +@property(nonatomic, assign) double cameraPitch; +@property(nonatomic, assign) float cameraZoom; +@property(nonatomic, assign) double cameraFOV; +@end diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSPanoramaLink.h b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSPanoramaLink.h new file mode 100644 index 0000000..f741d0e --- /dev/null +++ b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSPanoramaLink.h @@ -0,0 +1,23 @@ +// +// GMSPanoramaLink.h +// Google Maps SDK for iOS +// +// Copyright 2013 Google Inc. +// +// Usage of this SDK is subject to the Google Maps/Google Earth APIs Terms of +// Service: https://developers.google.com/maps/terms +// + +/** Links from a GMSPanorama to neighboring panoramas. */ +@interface GMSPanoramaLink : NSObject + +/** Angle of the neighboring panorama, clockwise from north in degrees. */ +@property(nonatomic, assign) CGFloat heading; + +/** + * Panorama ID for the neighboring panorama. + * Do not store this persistenly, it changes in time. + */ +@property(nonatomic, copy) NSString *panoramaID; + +@end diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSPanoramaService.h b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSPanoramaService.h new file mode 100644 index 0000000..0d72e61 --- /dev/null +++ b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSPanoramaService.h @@ -0,0 +1,52 @@ +// +// GMSPanoramaService.h +// Google Maps SDK for iOS +// +// Copyright 2013 Google Inc. +// +// Usage of this SDK is subject to the Google Maps/Google Earth APIs Terms of +// Service: https://developers.google.com/maps/terms +// + +#import + +@class GMSPanorama; + +/** + * Callback for when a panorama metadata becomes available. + * If an error occured, |panorama| is nil and |error| is not nil. + * Otherwise, |panorama| is not nil and |error| is nil. + */ +typedef void (^GMSPanoramaCallback)(GMSPanorama *panorama, NSError *error); + +/** + * GMSPanoramaService can be used to request panorama metadata even when a + * GMSPanoramaView is not active. + * Get an instance like this: [[GMSPanoramaService alloc] init]. + */ +@interface GMSPanoramaService : NSObject + +/** + * Retrieves information about a panorama near the given |coordinate|. + * This is an asynchronous request, |callback| will be called with the result. + */ +- (void)requestPanoramaNearCoordinate:(CLLocationCoordinate2D)coordinate + callback:(GMSPanoramaCallback)callback; + +/** + * Similar to requestPanoramaNearCoordinate:callback: but allows specifying + * a search radius (meters) around |coordinate|. + */ +- (void)requestPanoramaNearCoordinate:(CLLocationCoordinate2D)coordinate + radius:(NSUInteger)radius + callback:(GMSPanoramaCallback)callback; + +/** + * Retrieves information about a panorama with the given |panoramaID|. + * |callback| will be called with the result. Only panoramaIDs obtained + * from the Google Maps SDK for iOS are supported. + */ +- (void)requestPanoramaWithID:(NSString *)panoramaID + callback:(GMSPanoramaCallback)callback; + +@end diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSPanoramaView.h b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSPanoramaView.h new file mode 100644 index 0000000..cf3895d --- /dev/null +++ b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSPanoramaView.h @@ -0,0 +1,248 @@ +// +// GMSPanoramaView.h +// Google Maps SDK for iOS +// +// Copyright 2013 Google Inc. +// +// Usage of this SDK is subject to the Google Maps/Google Earth APIs Terms of +// Service: https://developers.google.com/maps/terms +// + +#import + +#import +#import + +@class GMSMarker; +@class GMSPanorama; +@class GMSPanoramaCamera; +@class GMSPanoramaCameraUpdate; +@class GMSPanoramaView; + +/** Delegate for events on GMSPanoramaView. */ +@protocol GMSPanoramaViewDelegate +@optional + +/** + * Called when starting a move to another panorama. + * This can be the result of interactive navigation to a neighbouring panorama. + * At the moment this method is called, the |view|.panorama is still + * pointing to the old panorama, as the new panorama identified by |panoID| + * is not yet resolved. panoramaView:didMoveToPanorama: will be called when the + * new panorama is ready. + */ +- (void)panoramaView:(GMSPanoramaView *)view + willMoveToPanoramaID:(NSString *)panoramaID; + +/** + * This is invoked every time the |view|.panorama property changes. + */ +- (void)panoramaView:(GMSPanoramaView *)view + didMoveToPanorama:(GMSPanorama *)panorama; + +/** + * Called when the panorama change was caused by invoking + * moveToPanoramaNearCoordinate:. The coordinate passed to that method will also + * be passed here. + */ +- (void)panoramaView:(GMSPanoramaView *)view + didMoveToPanorama:(GMSPanorama *)panorama + nearCoordinate:(CLLocationCoordinate2D)coordinate; + +/** + * Called when moveNearCoordinate: produces an error. + */ +- (void)panoramaView:(GMSPanoramaView *)view + error:(NSError *)error + onMoveNearCoordinate:(CLLocationCoordinate2D)coordinate; + +/** + * Called when moveToPanoramaID: produces an error. + */ +- (void)panoramaView:(GMSPanoramaView *)view + error:(NSError *)error + onMoveToPanoramaID:(NSString *)panoramaID; + +/** + * Called repeatedly during changes to the camera on GMSPanoramaView. This may + * not be called for all intermediate camera values, but is always called for + * the final position of the camera after an animation or gesture. + */ +- (void)panoramaView:(GMSPanoramaView *)panoramaView + didMoveCamera:(GMSPanoramaCamera *)camera; + +/** + * Called when a user has tapped on the GMSPanoramaView, but this tap was not + * consumed (taps may be consumed by e.g., tapping on a navigation arrow). + */ +- (void)panoramaView:(GMSPanoramaView *)panoramaView didTap:(CGPoint)point; + +/** + * Called after a marker has been tapped. May return YES to indicate the event + * has been fully handled and suppress any default behavior. + */ +- (BOOL)panoramaView:(GMSPanoramaView *)panoramaView + didTapMarker:(GMSMarker *)marker; + +@end + +/** + * A panorama is used to display Street View imagery. It should be constructed + * via [[GMSPanoramaView alloc] initWithFrame:], and configured + * post-initialization. + * + * All properties and methods should be accessed on the main thread, similar to + * all UIKit objects. The GMSPanoramaViewDelegate methods will also be called + * back only on the main thread. + * + * The backgroundColor of this view is shown while no panorama is visible, such + * as while it is loading or if the panorama is later set to nil. The alpha + * color of backgroundColor is not supported. + */ +@interface GMSPanoramaView : UIView + +/** + * The panorama to display; setting it will transition to a new panorama. This + * is animated, except for the initial panorama. + * + * Can be set to nil to clear the view. + */ +@property(nonatomic, strong) GMSPanorama *panorama; + +/** GMSPanoramaView delegate. */ +@property(nonatomic, weak) IBOutlet id delegate; + +/** + * Sets the preference for whether all gestures should be enabled (default) or + * disabled. + * This does not limit programmatic movement of the camera or control of the + * panorama. + */ +- (void)setAllGesturesEnabled:(BOOL)enabled; + +/** + * Controls whether orientation gestures are enabled (default) or disabled. If + * enabled, users may use gestures to change the orientation of the camera. + * This does not limit programmatic movement of the camera. + */ +@property(nonatomic, assign) BOOL orientationGestures; + +/** + * Controls whether zoom gestures are enabled (default) or disabled. If + * enabled, users may pinch to zoom the camera. + * This does not limit programmatic movement of the camera. + */ +@property(nonatomic, assign) BOOL zoomGestures; + +/** + * Controls whether navigation gestures are enabled (default) or disabled. If + * enabled, users may use a single tap on navigation links or double tap the + * view to change panoramas. + * This does not limit programmatic control of the panorama. + */ +@property(nonatomic, assign) BOOL navigationGestures; + +/** + * Controls whether the tappable navigation links are hidden or visible + * (default). + * Hidden navigation links cannot be tapped. + */ +@property(nonatomic, assign) BOOL navigationLinksHidden; + +/** + * Controls whether the street name overlays are hidden or visible (default). + */ +@property(nonatomic, assign) BOOL streetNamesHidden; + +/** + * Controls the panorama's camera. Setting a new camera here jumps to the new + * camera value, with no animation. + */ +@property(nonatomic, strong) GMSPanoramaCamera *camera; + +/** + * Accessor for the custom CALayer type used for the layer. + */ +@property(nonatomic, readonly, retain) GMSPanoramaLayer *layer; + +/** + * Animates the camera of this GMSPanoramaView to |camera|, over |duration| + * (specified in seconds). + */ +- (void)animateToCamera:(GMSPanoramaCamera *)camera + animationDuration:(NSTimeInterval)duration; + +/** + * Modifies the camera according to |cameraUpdate|, over |duration| (specified + * in seconds). + */ +- (void)updateCamera:(GMSPanoramaCameraUpdate *)cameraUpdate + animationDuration:(NSTimeInterval)duration; + +/** + * Requests a panorama near |coordinate|. + * Upon successful completion panoramaView:didMoveToPanorama: and + * panoramaView:didMoveToPanorama:nearCoordinate: will be sent to + * GMSPanoramaViewDelegate. + * On error panoramaView:error:onMoveNearCoordinate: will be sent. + * Repeated calls to moveNearCoordinate: result in the previous pending + * (incomplete) transitions being cancelled -- only the most recent of + * moveNearCoordinate: and moveToPanoramaId: will proceed and generate events. + */ +- (void)moveNearCoordinate:(CLLocationCoordinate2D)coordinate; + +/** + * Similar to moveNearCoordinate: but allows specifying a search radius (meters) + * around |coordinate|. + */ +- (void)moveNearCoordinate:(CLLocationCoordinate2D)coordinate + radius:(NSUInteger)radius; + +/** + * Requests a panorama with |panoramaID|. + * Upon successful completion panoramaView:didMoveToPanorama: will be sent to + * GMSPanoramaViewDelegate. + * On error panoramaView:error:onMoveToPanoramaID: will be sent. + * Repeated calls to moveToPanoramaID: result in the previous pending + * (incomplete) transitions being cancelled -- only the most recent of + * moveNearCoordinate: and moveToPanoramaId: will proceed and generate events. + * Only panoramaIDs obtained from the Google Maps SDK for iOS are supported. + */ +- (void)moveToPanoramaID:(NSString *)panoramaID; + +/** + * For the current view, returns the screen point the |orientation| points + * through. This value may be outside the view for forward facing orientations + * which are far enough away from straight ahead. + * The result will contain NaNs for camera orientations which point away from + * the view, where the implied screen point would have had a negative distance + * from the camera in the direction of orientation. + */ +- (CGPoint)pointForOrientation:(GMSOrientation)orientation; + +/** + * Given a point for this view, returns the current camera orientation pointing + * through that screen location. At the center of this view, the returned + * GMSOrientation will be approximately equal to that of the current + * GMSPanoramaCamera. + */ +- (GMSOrientation)orientationForPoint:(CGPoint)point; + +/** + * Convenience constructor for GMSPanoramaView, which searches for and displays + * a GMSPanorama near |coordinate|. This performs a similar action to that of + * moveNearCoordinate:, and will call the same delegate methods. + */ ++ (instancetype)panoramaWithFrame:(CGRect)frame + nearCoordinate:(CLLocationCoordinate2D)coordinate; + +/** + * Similar to panoramaWithFrame:nearCoordinate: but allows specifying a + * search radius (meters) around |coordinate|. + */ ++ (instancetype)panoramaWithFrame:(CGRect)frame + nearCoordinate:(CLLocationCoordinate2D)coordinate + radius:(NSUInteger)radius; + + +@end diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSPath.h b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSPath.h new file mode 100644 index 0000000..6b84012 --- /dev/null +++ b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSPath.h @@ -0,0 +1,103 @@ +// +// GMSPath.h +// Google Maps SDK for iOS +// +// Copyright 2013 Google Inc. +// +// Usage of this SDK is subject to the Google Maps/Google Earth APIs Terms of +// Service: https://developers.google.com/maps/terms +// + +#import + +/** + * GMSPath encapsulates an immutable array of CLLocationCooordinate2D. All the coordinates of a + * GMSPath must be valid. The mutable counterpart is GMSMutablePath. + */ +@interface GMSPath : NSObject + +/** Convenience constructor for an empty path. */ ++ (instancetype)path; + +/** Initializes a newly allocated path with the contents of another GMSPath. */ +- (id)initWithPath:(GMSPath *)path; + +/** Get size of path. */ +- (NSUInteger)count; + +/** Returns kCLLocationCoordinate2DInvalid if |index| >= count. */ +- (CLLocationCoordinate2D)coordinateAtIndex:(NSUInteger)index; + +/** + * Initializes a newly allocated path from |encodedPath|. This format is described at: + * https://developers.google.com/maps/documentation/utilities/polylinealgorithm + */ ++ (instancetype)pathFromEncodedPath:(NSString *)encodedPath; + +/** Returns an encoded string of the path in the format described above. */ +- (NSString *)encodedPath; + +/** + * Returns a new path obtained by adding |deltaLatitude| and |deltaLongitude| to each coordinate + * of the current path. Does not modify the current path. + */ +- (instancetype)pathOffsetByLatitude:(CLLocationDegrees)deltaLatitude + longitude:(CLLocationDegrees)deltaLongitude; + +@end + + +/** + * kGMSEquatorProjectedMeter may be useful when specifying lengths for segment in "projected" units. + * The value of kGMSEquatorProjectedMeter, 1/(pi * EarthRadius), represents the length of one meter + * at the equator in projected units. For example to specify a projected length that corresponds + * to 100km at the equator use 100000 * kGMSEquatorProjectedMeter. + * See [GMSPath segmentsForLength:kind:], [GMSPath lengthOfKind:] and kGMSLengthProjected. + */ +extern const double kGMSEquatorProjectedMeter; + +/** + * GMSLengthKind indicates the type of a length value, which can be geodesic (in meters), rhumb + * length (in meters) and projected length (in GMSMapPoint units). + */ +typedef enum { + /* + * Geodesic length, in meters, along geodesic segments. May be useful, for example, to specify + * lengths along the the trajectory of airplanes or ships. + */ + kGMSLengthGeodesic, + + /* + * Rhumb length, in meters, along rhumb (straight line) segments. May be useful, for example, to + * draw a scale bar on a map. The visual size of a segment of a given length depens on the + * latitude. + */ + kGMSLengthRhumb, + + /* + * Length in projected space, along rhumb segments. Projected length uses the same units as + * GMSMapPoint - the Earth equator circumference has length 2. It is possible to specify projected + * length in units corresponding to 1 meter at the equator by multiplying with + * kGMSEquatorProjectedMeter, equal to 1/(pi * EarthRadius). + * + * Projected length may be useful, for example, to specify segments with the same visual length + * regardless of latitude. + */ + kGMSLengthProjected +} GMSLengthKind; + + +@interface GMSPath (GMSPathLength) + +/** + * Returns the fractional number of segments along the path that correspond to |length|, + * interpreted according to |kind|. See GMSLengthKind. + */ +- (double)segmentsForLength:(CLLocationDistance)length kind:(GMSLengthKind)kind; + +/** + * Returns the length of the path, according to |kind|. See GMSLengthKind. + */ +- (CLLocationDistance)lengthOfKind:(GMSLengthKind)kind; + +@end diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSPlace.h b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSPlace.h new file mode 100644 index 0000000..ca2ad4c --- /dev/null +++ b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSPlace.h @@ -0,0 +1,109 @@ +// +// GMSPlace.h +// Google Maps SDK for iOS +// +// Copyright 2014 Google Inc. +// +// Usage of this SDK is subject to the Google Maps/Google Earth APIs Terms of +// Service: https://developers.google.com/maps/terms +// + +#import + +#import + +@class GMSPlaceUserData; + + +/** Describes the current open status of a place. */ +typedef NS_ENUM(NSInteger, GMSPlacesOpenNowStatus) { + /** The place is open now. */ + kGMSPlacesOpenNowStatusYes, + /** The place is not open now. */ + kGMSPlacesOpenNowStatusNo, + /** We don't know whether the place is open now. */ + kGMSPlacesOpenNowStatusUnknown, +}; + +typedef NS_ENUM(NSInteger, GMSPlacesPriceLevel) { + kGMSPlacesPriceLevelUnknown = -1, + kGMSPlacesPriceLevelFree = 0, + kGMSPlacesPriceLevelCheap = 1, + kGMSPlacesPriceLevelMedium = 2, + kGMSPlacesPriceLevelHigh = 3, + kGMSPlacesPriceLevelExpensive = 4, +}; + +/** + * Represents a particular physical place. A GMSPlace encapsulates information about a physical + * location, including its name, location, and any other information we might have about it. This + * class is immutable. + */ +@interface GMSPlace : NSObject + +/** Name of the place. */ +@property(nonatomic, copy, readonly) NSString *name; + +/** Place ID of this place. */ +@property(nonatomic, copy, readonly) NSString *placeID; + +/** + * Location of the place. The location is not necessarily the center of the Place, or any + * particular entry or exit point, but some arbitrarily chosen point within the geographic extent of + * the Place. + */ +@property(nonatomic, readonly) CLLocationCoordinate2D coordinate; + +/** + * Represents the open now status of the place at the time that the place was created. + */ +@property(nonatomic, readonly) GMSPlacesOpenNowStatus openNowStatus; + +/** + * Phone number of this place, in international format, i.e. including the country code prefixed + * with "+". For example, Google Sydney's phone number is "+61 2 9374 4000". + */ +@property(nonatomic, copy, readonly) NSString *phoneNumber; + +/** + * Address of the place as a simple string. + */ +@property(nonatomic, copy, readonly) NSString *formattedAddress; + +/** + * Five-star rating for this place based on user reviews. + * + * Ratings range from 1.0 to 5.0. 0.0 means we have no rating for this place (e.g. because not + * enough users have reviewed this place). + */ +@property(nonatomic, readonly) float rating; + +/** + * Price level for this place, as integers from 0 to 4. + * + * e.g. A value of 4 means this place is "$$$$" (expensive). A value of 0 means free (such as a + * museum with free admission). + */ +@property(nonatomic, readonly) GMSPlacesPriceLevel priceLevel; + +/** + * The types of this place. Types are NSStrings, valid values are any types documented at + * . + */ +@property(nonatomic, copy, readonly) NSArray *types; + +/** Website for this place. */ +@property(nonatomic, copy, readonly) NSURL *website; + +/** + * The data provider attribution string for this place. + * + * These are provided as a NSAttributedString, which may contain hyperlinks to the website of each + * provider. + * + * In general, these must be shown to the user if data from this GMSPlace is shown, as described in + * the Places API Terms of Service. + */ +@property(nonatomic, copy, readonly) NSAttributedString *attributions; + +@end diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSPlaceLikelihood.h b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSPlaceLikelihood.h new file mode 100644 index 0000000..e7a059a --- /dev/null +++ b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSPlaceLikelihood.h @@ -0,0 +1,35 @@ +// +// GMSPlaceLikelihood.h +// Google Maps SDK for iOS +// +// Copyright 2014 Google Inc. +// +// Usage of this SDK is subject to the Google Maps/Google Earth APIs Terms of +// Service: https://developers.google.com/maps/terms +// + + +@class GMSPlace; + +/** + * Represents a |GMSPlace| and the relative likelihood of the place being the best match within the + * list of returned places for a single request. For more information about place likelihoods, see + * |GMSPlaceLikelihoodList|. + */ +@interface GMSPlaceLikelihood : NSObject + +/** + * The place contained in this place likelihood. + */ +@property(nonatomic, strong, readonly) GMSPlace *place; + +/** + * Returns a value from 0.0 to 1.0 indicating the confidence that the user is at this place. The + * larger the value the more confident we are of the place returned. For example, a likelihood of + * 0.75 means that the user is at least 75% likely to be at this place. + */ +@property(nonatomic, assign, readonly) double likelihood; + +- (instancetype)initWithPlace:(GMSPlace *)place likelihood:(double)likelihood; + +@end diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSPlaceLikelihoodList.h b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSPlaceLikelihoodList.h new file mode 100644 index 0000000..1baadf1 --- /dev/null +++ b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSPlaceLikelihoodList.h @@ -0,0 +1,34 @@ +// +// GMSPlaceLikelihoodList.h +// Google Maps SDK for iOS +// +// Copyright 2014 Google Inc. +// +// Usage of this SDK is subject to the Google Maps/Google Earth APIs Terms of +// Service: https://developers.google.com/maps/terms +// + +/** + * Represents a list of places with an associated likelihood for the place being the correct place. + * For example, the Places service may be uncertain what the true Place is, but think it 55% likely + * to be PlaceA, and 35% likely to be PlaceB. The corresponding likelihood list has two members, one + * with likelihood 0.55 and the other with likelihood 0.35. The likelihoods are not guaranteed to be + * correct, and in a given place likelihood list they may not sum to 1.0. + */ +@interface GMSPlaceLikelihoodList : NSObject + +/** An array of |GMSPlaceLikelihood|s containing the likelihoods in the list. */ +@property(nonatomic, copy) NSArray *likelihoods; + +/** + * The data provider attribution strings for the likelihood list. + * + * These are provided as a NSAttributedString, which may contain hyperlinks to the website of each + * provider. + * + * In general, these must be shown to the user if data from this likelihood list is shown, as + * described in the Places API Terms of Service. + */ +@property(nonatomic, copy, readonly) NSAttributedString *attributions; + +@end diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSPlacePicker.h b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSPlacePicker.h new file mode 100644 index 0000000..2edfb89 --- /dev/null +++ b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSPlacePicker.h @@ -0,0 +1,72 @@ +// +// GMSPlacePicker.h +// Google Maps SDK for iOS +// +// Copyright 2014 Google Inc. +// +// Usage of this SDK is subject to the Google Maps/Google Earth APIs Terms of +// Service: https://developers.google.com/maps/terms +// + +#import + + +/* Error domain used for Place Picker errors. */ +extern NSString * const kGMSPlacePickerErrorDomain; + +/* Error codes for |kGMSPlacePickerErrorDomain|. */ +typedef NS_ENUM(NSInteger, GMSPlacePickerErrorCode) { + /** + * Something unknown went wrong. + */ + kGMSPlacePickerUnknownError = -1, + /** + * An internal error occurred in the Places API library. + */ + kGMSPlacePickerInternalError = -2, + /** + * An invalid GMSPlacePickerConfig was used. + */ + kGMSPlacePickerInvalidConfig = -3, + /** + * Attempted to perform simultaneous place picking operations. + */ + kGMSPlacePickerOverlappingCalls = -4, +}; + +/** + * The Place Picker is a dialog that allows the user to pick a |GMSPlace| using an interactive map + * and other tools. Users can select the place they're at or nearby. + */ +@interface GMSPlacePicker : NSObject + +/** + * The configuration of the place picker, as passed in at initialization. + */ +@property(nonatomic, readonly, copy) GMSPlacePickerConfig *config; + +/** + * Initializes the place picker with a given configuration. This does not start the process of + * picking a place. + */ +- (instancetype)initWithConfig:(GMSPlacePickerConfig *)config; + +/** + * Prompt the user to pick a place. The place picker is a full-screen window that appears on + * [UIScreen mainScreen]. The place picker takes over the screen until the user cancels the + * operation or picks a place. The supplied callback will be invoked with the chosen place, or nil + * if no place was chosen. + * + * This method should be called on the main thread. The callback will also be invoked on the main + * thread. + * + * It is not possible to have multiple place picking operations active at the same time. If this is + * attempted, the second callback will be invoked with an error. + * + * A reference to the place picker must be retained for the duration of the place picking operation. + * If the retain count of the place picker object becomes 0, the picking operation will be cancelled + * and the callback will not be invoked. + */ +- (void)pickPlaceWithCallback:(GMSPlaceResultCallback)callback; + +@end diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSPlacePickerConfig.h b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSPlacePickerConfig.h new file mode 100644 index 0000000..bf9da34 --- /dev/null +++ b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSPlacePickerConfig.h @@ -0,0 +1,31 @@ +// +// GMSPlacePickerConfig.h +// Google Maps SDK for iOS +// +// Copyright 2014 Google Inc. +// +// Usage of this SDK is subject to the Google Maps/Google Earth APIs Terms of +// Service: https://developers.google.com/maps/terms +// + +#import +#import + + +/** + * Configuration object used to change the behaviour of the place picker. + */ +@interface GMSPlacePickerConfig : NSObject + +/** + * The initial viewport that the place picker map should show. If this is nil, a sensible default + * will be chosen based on the user's location. + */ +@property(nonatomic, strong, readonly) GMSCoordinateBounds *viewport; + +/** + * Initialize the configuration. + */ +- (instancetype)initWithViewport:(GMSCoordinateBounds *)viewport; + +@end diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSPlaceTypes.h b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSPlaceTypes.h new file mode 100644 index 0000000..574a715 --- /dev/null +++ b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSPlaceTypes.h @@ -0,0 +1,137 @@ +// +// GMSPlaceTypes.h +// Google Maps SDK for iOS +// +// Copyright 2014 Google Inc. +// +// Usage of this SDK is subject to the Google Maps/Google Earth APIs Terms of +// Service: https://developers.google.com/maps/terms +// + + + +extern NSString *const kGMSPlaceTypeAccounting; +extern NSString *const kGMSPlaceTypeAdministrativeAreaLevel1; +extern NSString *const kGMSPlaceTypeAdministrativeAreaLevel2; +extern NSString *const kGMSPlaceTypeAdministrativeAreaLevel3; +extern NSString *const kGMSPlaceTypeAirport; +extern NSString *const kGMSPlaceTypeAmusementPark; +extern NSString *const kGMSPlaceTypeAquarium; +extern NSString *const kGMSPlaceTypeArtGallery; +extern NSString *const kGMSPlaceTypeAtm; +extern NSString *const kGMSPlaceTypeBakery; +extern NSString *const kGMSPlaceTypeBank; +extern NSString *const kGMSPlaceTypeBar; +extern NSString *const kGMSPlaceTypeBeautySalon; +extern NSString *const kGMSPlaceTypeBicycleStore; +extern NSString *const kGMSPlaceTypeBookStore; +extern NSString *const kGMSPlaceTypeBowlingAlley; +extern NSString *const kGMSPlaceTypeBusStation; +extern NSString *const kGMSPlaceTypeCafe; +extern NSString *const kGMSPlaceTypeCampground; +extern NSString *const kGMSPlaceTypeCarDealer; +extern NSString *const kGMSPlaceTypeCarRental; +extern NSString *const kGMSPlaceTypeCarRepair; +extern NSString *const kGMSPlaceTypeCarWash; +extern NSString *const kGMSPlaceTypeCasino; +extern NSString *const kGMSPlaceTypeCemetery; +extern NSString *const kGMSPlaceTypeChurch; +extern NSString *const kGMSPlaceTypeCityHall; +extern NSString *const kGMSPlaceTypeClothingStore; +extern NSString *const kGMSPlaceTypeColloquialArea; +extern NSString *const kGMSPlaceTypeConvenienceStore; +extern NSString *const kGMSPlaceTypeCountry; +extern NSString *const kGMSPlaceTypeCourthouse; +extern NSString *const kGMSPlaceTypeDentist; +extern NSString *const kGMSPlaceTypeDepartmentStore; +extern NSString *const kGMSPlaceTypeDoctor; +extern NSString *const kGMSPlaceTypeElectrician; +extern NSString *const kGMSPlaceTypeElectronicsStore; +extern NSString *const kGMSPlaceTypeEmbassy; +extern NSString *const kGMSPlaceTypeEstablishment; +extern NSString *const kGMSPlaceTypeFinance; +extern NSString *const kGMSPlaceTypeFireStation; +extern NSString *const kGMSPlaceTypeFloor; +extern NSString *const kGMSPlaceTypeFlorist; +extern NSString *const kGMSPlaceTypeFood; +extern NSString *const kGMSPlaceTypeFuneralHome; +extern NSString *const kGMSPlaceTypeFurnitureStore; +extern NSString *const kGMSPlaceTypeGasStation; +extern NSString *const kGMSPlaceTypeGeneralContractor; +extern NSString *const kGMSPlaceTypeGeocode; +extern NSString *const kGMSPlaceTypeGroceryOrSupermarket; +extern NSString *const kGMSPlaceTypeGym; +extern NSString *const kGMSPlaceTypeHairCare; +extern NSString *const kGMSPlaceTypeHardwareStore; +extern NSString *const kGMSPlaceTypeHealth; +extern NSString *const kGMSPlaceTypeHinduTemple; +extern NSString *const kGMSPlaceTypeHomeGoodsStore; +extern NSString *const kGMSPlaceTypeHospital; +extern NSString *const kGMSPlaceTypeInsuranceAgency; +extern NSString *const kGMSPlaceTypeIntersection; +extern NSString *const kGMSPlaceTypeJewelryStore; +extern NSString *const kGMSPlaceTypeLaundry; +extern NSString *const kGMSPlaceTypeLawyer; +extern NSString *const kGMSPlaceTypeLibrary; +extern NSString *const kGMSPlaceTypeLiquorStore; +extern NSString *const kGMSPlaceTypeLocalGovernmentOffice; +extern NSString *const kGMSPlaceTypeLocality; +extern NSString *const kGMSPlaceTypeLocksmith; +extern NSString *const kGMSPlaceTypeLodging; +extern NSString *const kGMSPlaceTypeMealDelivery; +extern NSString *const kGMSPlaceTypeMealTakeaway; +extern NSString *const kGMSPlaceTypeMosque; +extern NSString *const kGMSPlaceTypeMovieRental; +extern NSString *const kGMSPlaceTypeMovieTheater; +extern NSString *const kGMSPlaceTypeMovingCompany; +extern NSString *const kGMSPlaceTypeMuseum; +extern NSString *const kGMSPlaceTypeNaturalFeature; +extern NSString *const kGMSPlaceTypeNeighborhood; +extern NSString *const kGMSPlaceTypeNightClub; +extern NSString *const kGMSPlaceTypePainter; +extern NSString *const kGMSPlaceTypePark; +extern NSString *const kGMSPlaceTypeParking; +extern NSString *const kGMSPlaceTypePetStore; +extern NSString *const kGMSPlaceTypePharmacy; +extern NSString *const kGMSPlaceTypePhysiotherapist; +extern NSString *const kGMSPlaceTypePlaceOfWorship; +extern NSString *const kGMSPlaceTypePlumber; +extern NSString *const kGMSPlaceTypePointOfInterest; +extern NSString *const kGMSPlaceTypePolice; +extern NSString *const kGMSPlaceTypePolitical; +extern NSString *const kGMSPlaceTypePostBox; +extern NSString *const kGMSPlaceTypePostOffice; +extern NSString *const kGMSPlaceTypePostalCode; +extern NSString *const kGMSPlaceTypePostalCodePrefix; +extern NSString *const kGMSPlaceTypePostalTown; +extern NSString *const kGMSPlaceTypePremise; +extern NSString *const kGMSPlaceTypeRealEstateAgency; +extern NSString *const kGMSPlaceTypeRestaurant; +extern NSString *const kGMSPlaceTypeRoofingContractor; +extern NSString *const kGMSPlaceTypeRoom; +extern NSString *const kGMSPlaceTypeRoute; +extern NSString *const kGMSPlaceTypeRvPark; +extern NSString *const kGMSPlaceTypeSchool; +extern NSString *const kGMSPlaceTypeShoeStore; +extern NSString *const kGMSPlaceTypeShoppingMall; +extern NSString *const kGMSPlaceTypeSpa; +extern NSString *const kGMSPlaceTypeStadium; +extern NSString *const kGMSPlaceTypeStorage; +extern NSString *const kGMSPlaceTypeStore; +extern NSString *const kGMSPlaceTypeStreetAddress; +extern NSString *const kGMSPlaceTypeSublocality; +extern NSString *const kGMSPlaceTypeSublocalityLevel1; +extern NSString *const kGMSPlaceTypeSublocalityLevel2; +extern NSString *const kGMSPlaceTypeSublocalityLevel3; +extern NSString *const kGMSPlaceTypeSublocalityLevel4; +extern NSString *const kGMSPlaceTypeSublocalityLevel5; +extern NSString *const kGMSPlaceTypeSubpremise; +extern NSString *const kGMSPlaceTypeSubwayStation; +extern NSString *const kGMSPlaceTypeSynagogue; +extern NSString *const kGMSPlaceTypeTaxiStand; +extern NSString *const kGMSPlaceTypeTrainStation; +extern NSString *const kGMSPlaceTypeTransitStation; +extern NSString *const kGMSPlaceTypeTravelAgency; +extern NSString *const kGMSPlaceTypeUniversity; +extern NSString *const kGMSPlaceTypeVeterinaryCare; +extern NSString *const kGMSPlaceTypeZoo; diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSPlacesClient.h b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSPlacesClient.h new file mode 100644 index 0000000..a7ef2ae --- /dev/null +++ b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSPlacesClient.h @@ -0,0 +1,192 @@ +// +// GMSPlacesClient.h +// Google Maps SDK for iOS +// +// Copyright 2014 Google Inc. +// +// Usage of this SDK is subject to the Google Maps/Google Earth APIs Terms of +// Service: https://developers.google.com/maps/terms +// + +#import + +#import +#import +#import + + +@class GMSAutocompleteFilter; +@class GMSPlaceLikelihoodList; + +GMS_ASSUME_NONNULL_BEGIN + +/* Error domain used for Places API errors. */ +extern NSString * const kGMSPlacesErrorDomain; + +/* Error codes for |kGMSPlacesErrorDomain|. */ +typedef NS_ENUM(NSInteger, GMSPlacesErrorCode) { + /** + * Something went wrong with the connection to the Places API server. + */ + kGMSPlacesNetworkError = -1, + /** + * The Places API server returned a response that we couldn't understand. + */ + kGMSPlacesServerError = -2, + /** + * An internal error occurred in the Places API library. + */ + kGMSPlacesInternalError = -3, + /** + * Operation failed due to an invalid (malformed or missing) API key. + *

+ * See the developer's guide + * for information on creating and using an API key. + */ + kGMSPlacesKeyInvalid = -4, + /** + * Operation failed due to an expired API key. + *

+ * See the developer's guide + * for information on creating and using an API key. + */ + kGMSPlacesKeyExpired = -5, + /** + * Operation failed due to exceeding the quota usage limit. + *

+ * See the developer's guide + * for information on usage limits and how to request a higher limit. + */ + kGMSPlacesUsageLimitExceeded = -6, + /** + * Operation failed due to exceeding the usage rate limit for the API key. + *

+ * This status code shouldn't be returned during normal usage of the API. It relates to usage of + * the API that far exceeds normal request levels. + */ + kGMSPlacesRateLimitExceeded = -7, + /** + * Operation failed due to exceeding the per-device usage rate limit. + *

+ * This status code shouldn't be returned during normal usage of the API. It relates to usage of + * the API that far exceeds normal request levels. + */ + kGMSPlacesDeviceRateLimitExceeded = -8, + /** + * The Places API is not enabled. + *

+ * See the developer's guide for how + * to enable the Google Places API for iOS. + */ + kGMSPlacesAccessNotConfigured = -9, + /** + * The application's bundle identifier does not match one of the allowed iOS applications for the + * API key. + *

+ * See the developer's guide + * for how to configure bundle restrictions on API keys. + */ + kGMSPlacesIncorrectBundleIdentifier = -10 +}; + +/** + * @relates GMSPlacesClient + * Callback type for receiving place details lookups. If an error occurred, + * |result| will be nil and |error| will contain information about the error. + * @param result The |GMSPlace| that was returned. + * @param error The error that occured, if any. + */ +typedef void (^GMSPlaceResultCallback)( + GMSPlace * GMS_NULLABLE_PTR result, + NSError * GMS_NULLABLE_PTR error); + +/** + * @relates GMSPlacesClient + * Callback type for receiving place likelihood lists. If an error occurred, |likelihoodList| will + * be nil and |error| will contain information about the error. + * @param likelihoodList The list of place likelihoods. + * @param error The error that occured, if any. + */ +typedef void (^GMSPlaceLikelihoodListCallback)( + GMSPlaceLikelihoodList * GMS_NULLABLE_PTR likelihoodList, + NSError * GMS_NULLABLE_PTR error); + +/** + * @relates GMSPlacesClient + * Callback type for receiving autocompletion results. |results| is an array of + * GMSAutocompletePredictions representing candidate completions of the query. + * @param results An array of |GMSAutocompletePrediction|s. + * @param error The error that occured, if any. + */ +typedef void (^GMSAutocompletePredictionsCallback)( + NSArray * GMS_NULLABLE_PTR results, + NSError * GMS_NULLABLE_PTR error); + +/** + * Main interface to the Places API. Used for searching and getting details about places. This class + * should be accessed through the [GMSPlacesClient sharedClient] method. + * + * GMSPlacesClient methods should only be called from the main thread. Calling these methods from + * another thread will result in an exception or undefined behavior. Unless otherwise specified, all + * callbacks will be invoked on the main thread. + */ +@interface GMSPlacesClient : NSObject + +/** + * Provides the shared instance of GMSPlacesClient for the Google Maps SDK for iOS, + * creating it if necessary. + * + * If your application often uses methods of GMSPlacesClient it may want to hold + * onto this object directly, as otherwise your connection to Google may be restarted + * on a regular basis. + */ ++ (instancetype)sharedClient; + +/** + * Report that the device is at a particular place. + */ +- (void)reportDeviceAtPlaceWithID:(NSString *)placeID; + +/** + * Get details for a place. This method is non-blocking. + * @param placeID The place ID to lookup. + * @param callback The callback to invoke with the lookup result. + */ +- (void)lookUpPlaceID:(NSString *)placeID callback:(GMSPlaceResultCallback)callback; + +/** + * Returns an estimate of the place where the device is currently known to be located. + * + * Generates a place likelihood list based on the device's last estimated location. The supplied + * callback will be invoked with this likelihood list upon success and an NSError upon an error. + * @param callback The callback to invoke with the place likelihood list. + */ +- (void)currentPlaceWithCallback:(GMSPlaceLikelihoodListCallback)callback; + +/** + * Autocompletes a given text query. Results may optionally be biased towards a certain location. + * The supplied callback will be invoked with an array of autocompletion predictions upon success + * and an NSError upon an error. + * @param query The partial text to autocomplete. + * @param bounds The bounds used to bias the results. This is not a hard restrict - places may still + * be returned outside of these bounds. This parameter may be nil. + * @param filter The filter to apply to the results. This parameter may be nil. + * @param callback The callback to invoke with the predictions. + */ +- (void)autocompleteQuery:(NSString *)query + bounds:(GMSCoordinateBounds * GMS_NULLABLE_PTR)bounds + filter:(GMSAutocompleteFilter * GMS_NULLABLE_PTR)filter + callback:(GMSAutocompletePredictionsCallback)callback; + +/** + * Add a place. The |place| must have all its fields set, except that website or phoneNumber may be + * nil. + * @param place The details of the place to be added. + * @param callback The callback to invoke with the place that was added. + */ +- (void)addPlace:(GMSUserAddedPlace *)place + callback:(GMSPlaceResultCallback)callback; + +@end + +GMS_ASSUME_NONNULL_END diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSPlacesMacros.h b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSPlacesMacros.h new file mode 100644 index 0000000..76206be --- /dev/null +++ b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSPlacesMacros.h @@ -0,0 +1,23 @@ +// +// GMSPlacesMacros.h +// Google Maps SDK for iOS +// +// Copyright 2015 Google Inc. +// +// Usage of this SDK is subject to the Google Maps/Google Earth APIs Terms of +// Service: https://developers.google.com/maps/terms +// + +#if !__has_feature(nullability) \ + || !defined(NS_ASSUME_NONNULL_BEGIN) \ + || !defined(NS_ASSUME_NONNULL_END) +#define GMS_ASSUME_NONNULL_BEGIN +#define GMS_ASSUME_NONNULL_END +#define GMS_NULLABLE +#define GMS_NULLABLE_PTR +#else +#define GMS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN +#define GMS_ASSUME_NONNULL_END NS_ASSUME_NONNULL_END +#define GMS_NULLABLE nullable +#define GMS_NULLABLE_PTR __nullable +#endif diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSPolygon.h b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSPolygon.h new file mode 100644 index 0000000..7bc115b --- /dev/null +++ b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSPolygon.h @@ -0,0 +1,43 @@ +// +// GMSPolygon.h +// Google Maps SDK for iOS +// +// Copyright 2013 Google Inc. +// +// Usage of this SDK is subject to the Google Maps/Google Earth APIs Terms of +// Service: https://developers.google.com/maps/terms +// + +#import + +@class GMSPath; + +/** + * GMSPolygon defines a polygon that appears on the map. A polygon (like a polyline) defines a + * series of connected coordinates in an ordered sequence; additionally, polygons form a closed loop + * and define a filled region. + */ +@interface GMSPolygon : GMSOverlay + +/** The path that describes this polygon. The coordinates composing the path must be valid. */ +@property(nonatomic, copy) GMSPath *path; + +/** The width of the polygon outline in screen points. Defaults to 1. */ +@property(nonatomic, assign) CGFloat strokeWidth; + +/** The color of the polygon outline. Defaults to nil. */ +@property(nonatomic, strong) UIColor *strokeColor; + +/** The fill color. Defaults to blueColor. */ +@property(nonatomic, strong) UIColor *fillColor; + +/** Whether this polygon should be rendered with geodesic correction. */ +@property(nonatomic, assign) BOOL geodesic; + +/** + * Convenience constructor for GMSPolygon for a particular path. Other properties will have default + * values. + */ ++ (instancetype)polygonWithPath:(GMSPath *)path; + +@end diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSPolyline.h b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSPolyline.h new file mode 100644 index 0000000..704e4f0 --- /dev/null +++ b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSPolyline.h @@ -0,0 +1,102 @@ +// +// GMSPolyline.h +// Google Maps SDK for iOS +// +// Copyright 2012 Google Inc. +// +// Usage of this SDK is subject to the Google Maps/Google Earth APIs Terms of +// Service: https://developers.google.com/maps/terms +// + +#import + +@class GMSPath; + +/** Describes the drawing style for one-dimensional entities such as polylines. */ +@interface GMSStrokeStyle : NSObject + +/** Creates a solid color stroke style. */ ++ (instancetype)solidColor:(UIColor *)color; + +/** Creates a gradient stroke style interpolating from |fromColor| to |toColor|. */ ++ (instancetype)gradientFromColor:(UIColor *)fromColor toColor:(UIColor *)toColor; + +@end + + +/** Describes the style for some region of a polyline. */ +@interface GMSStyleSpan : NSObject + +/** + * Factory returning a solid color span of length one segment. Equivalent to + * [GMSStyleSpan spanWithStyle:[GMSStrokeStyle solidColor:|color|] segments:1]. + */ ++ (instancetype)spanWithColor:(UIColor *)color; + +/** + * Factory returning a solid color span with a given number of segments. Equivalent to + * [GMSStyleSpan spanWithStyle:[GMSStrokeStyle solidColor:|color|] segments:|segments|]. + */ ++ (instancetype)spanWithColor:(UIColor *)color segments:(double)segments; + +/** + * Factory returning a span with the given |style| of length one segment. Equivalent to + * [GMSStyleSpan spanWithStyle:|style| segments:1]. + */ ++ (instancetype)spanWithStyle:(GMSStrokeStyle *)style; + +/** + * Factory returning a span with the given |style| and length in number of segments. + * |segments| must be greater than 0 (i.e. can't be 0). + */ ++ (instancetype)spanWithStyle:(GMSStrokeStyle *)style segments:(double)segments; + +/** The style of this span. */ +@property(nonatomic, readonly) GMSStrokeStyle *style; + +/** The length of this span in number of segments. */ +@property(nonatomic, readonly) double segments; + +@end + + +/** + * GMSPolyline specifies the available options for a polyline that exists on the Earth's surface. + * It is drawn as a physical line between the points specified in |path|. + */ +@interface GMSPolyline : GMSOverlay + +/** + * The path that describes this polyline. + */ +@property(nonatomic, copy) GMSPath *path; + +/** + * The width of the line in screen points. Defaults to 1. + */ +@property(nonatomic, assign) CGFloat strokeWidth; + +/** + * The UIColor used to render the polyline. Defaults to [UIColor blueColor]. + */ +@property(nonatomic, strong) UIColor *strokeColor; + +/** Whether this line should be rendered with geodesic correction. */ +@property(nonatomic, assign) BOOL geodesic; + +/** + * Convenience constructor for GMSPolyline for a particular path. Other properties will have + * default values. + */ ++ (instancetype)polylineWithPath:(GMSPath *)path; + +/** + * An array containing GMSStyleSpan, the spans used to render this polyline. + * + * If this array contains fewer segments than the polyline itself, the final segment will be applied + * over the remaining length. If this array is unset or empty, then |strokeColor| is used for the + * entire line instead. + */ +@property(nonatomic, copy) NSArray *spans; + +@end diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSProjection.h b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSProjection.h new file mode 100644 index 0000000..7596dba --- /dev/null +++ b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSProjection.h @@ -0,0 +1,75 @@ +// +// GMSProjection.h +// Google Maps SDK for iOS +// +// Copyright 2012 Google Inc. +// +// Usage of this SDK is subject to the Google Maps/Google Earth APIs Terms of +// Service: https://developers.google.com/maps/terms +// + +#import + +/** + * GMSVisibleRegion contains the four points defining the polygon that is visible in a map's camera. + * + * This polygon can be a trapezoid instead of a rectangle, because a camera can have tilt. If the + * camera is directly over the center of the camera, the shape is rectangular, but if the camera is + * tilted, the shape will appear to be a trapezoid whose smallest side is closest to the point of + * view. + */ +typedef struct { + + /** Bottom left corner of the camera. */ + CLLocationCoordinate2D nearLeft; + + /** Bottom right corner of the camera. */ + CLLocationCoordinate2D nearRight; + + /** Far left corner of the camera. */ + CLLocationCoordinate2D farLeft; + + /** Far right corner of the camera. */ + CLLocationCoordinate2D farRight; +} GMSVisibleRegion; + +/** + * Defines a mapping between Earth coordinates (CLLocationCoordinate2D) and coordinates in the map's + * view (CGPoint). A projection is constant and immutable, in that the mapping it embodies never + * changes. The mapping is not necessarily linear. + * + * Passing invalid Earth coordinates (i.e., per CLLocationCoordinate2DIsValid) to this object may + * result in undefined behavior. + * + * This class should not be instantiated directly, instead, obtained via projection on GMSMapView. + */ +@interface GMSProjection : NSObject + +/** Maps an Earth coordinate to a point coordinate in the map's view. */ +- (CGPoint)pointForCoordinate:(CLLocationCoordinate2D)coordinate; + +/** Maps a point coordinate in the map's view to an Earth coordinate. */ +- (CLLocationCoordinate2D)coordinateForPoint:(CGPoint)point; + +/** + * Converts a distance in meters to content size. This is only accurate for small Earth distances, + * as it uses CGFloat for screen distances. + */ +- (CGFloat)pointsForMeters:(CLLocationDistance)meters + atCoordinate:(CLLocationCoordinate2D)coordinate; + +/** + * Returns whether a given coordinate (lat/lng) is contained within the projection. + */ +- (BOOL)containsCoordinate:(CLLocationCoordinate2D)coordinate; + +/** + * Returns the region (four location coordinates) that is visible according to the projection. If + * padding was set on GMSMapView, this region takes the padding into account. + * + * The visible region can be non-rectangular. The result is undefined if the projection includes + * points that do not map to anywhere on the map (e.g., camera sees outer space). + */ +- (GMSVisibleRegion)visibleRegion; + +@end diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSServices.h b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSServices.h new file mode 100644 index 0000000..1829236 --- /dev/null +++ b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSServices.h @@ -0,0 +1,51 @@ +// +// GMSServices.h +// Google Maps SDK for iOS +// +// Copyright 2012 Google Inc. +// +// Usage of this SDK is subject to the Google Maps/Google Earth APIs Terms of +// Service: https://developers.google.com/maps/terms +// + +/** Service class for the Google Maps SDK for iOS. */ +@interface GMSServices : NSObject + +/** + * Provides the shared instance of GMSServices for the Google Maps SDK for iOS, + * creating it if necessary. Classes such as GMSMapView and GMSPanoramaView will + * hold this instance to provide their connection to Google. + * + * This is an opaque object. If your application often creates and destroys view + * or service classes provided by the Google Maps SDK for iOS, it may be useful + * to hold onto this object directly, as otherwise your connection to Google + * may be restarted on a regular basis. It also may be useful to take this + * object in advance of the first map creation, to reduce initial map creation + * performance cost. + * + * This method will throw an exception if provideAPIKey: has not been called. + */ ++ (id)sharedServices; + +/** + * Provides your API key to the Google Maps SDK for iOS. This key is generated + * for your application via the Google APIs Console, and is paired with your + * application's bundle ID to identify it. This should be called exactly once + * by your application, e.g., in application: didFinishLaunchingWithOptions:. + * + * @return YES if the APIKey was successfully provided + */ ++ (BOOL)provideAPIKey:(NSString *)APIKey; + +/** + * Returns the open source software license information for Google Maps SDK for + * iOS. This information must be made available within your application. + */ ++ (NSString *)openSourceLicenseInfo; + +/** + * Returns the version for this release of the Google Maps SDK for iOS. + */ ++ (NSString *)SDKVersion; + +@end diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSSyncTileLayer.h b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSSyncTileLayer.h new file mode 100644 index 0000000..c0671d9 --- /dev/null +++ b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSSyncTileLayer.h @@ -0,0 +1,29 @@ +// +// GMSSyncTileLayer.h +// Google Maps SDK for iOS +// +// Copyright 2013 Google Inc. +// +// Usage of this SDK is subject to the Google Maps/Google Earth APIs Terms of +// Service: https://developers.google.com/maps/terms +// + +#import + +/** + * GMSSyncTileLayer is an abstract subclass of GMSTileLayer that provides a sync + * interface to generate image tile data. + */ +@interface GMSSyncTileLayer : GMSTileLayer + +/** + * As per requestTileForX:y:zoom:receiver: on GMSTileLayer, but provides a + * synchronous interface to return tiles. This method may block or otherwise + * perform work, and is not called on the main thread. + * + * Calls to this method may also be made from multiple threads so + * implementations must be threadsafe. + */ +- (UIImage *)tileForX:(NSUInteger)x y:(NSUInteger)y zoom:(NSUInteger)zoom; + +@end diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSTileLayer.h b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSTileLayer.h new file mode 100644 index 0000000..20bf77b --- /dev/null +++ b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSTileLayer.h @@ -0,0 +1,103 @@ +// +// GMSTileLayer.h +// Google Maps SDK for iOS +// +// Copyright 2013 Google Inc. +// +// Usage of this SDK is subject to the Google Maps/Google Earth APIs Terms of +// Service: https://developers.google.com/maps/terms +// + +@class GMSMapView; + +/** + * Stub tile that is used to indicate that no tile exists for a specific tile + * coordinate. May be returned by tileForX:y:zoom: on GMSTileProvider. + */ +FOUNDATION_EXTERN UIImage *const kGMSTileLayerNoTile; + +/** + * GMSTileReceiver is provided to GMSTileLayer when a tile request is made, + * allowing the callback to be later (or immediately) invoked. + */ +@protocol GMSTileReceiver +- (void)receiveTileWithX:(NSUInteger)x + y:(NSUInteger)y + zoom:(NSUInteger)zoom + image:(UIImage *)image; +@end + +/** + * GMSTileLayer is an abstract class that allows overlaying of custom image + * tiles on a specified GMSMapView. It may not be initialized directly, and + * subclasses must implement the tileForX:y:zoom: method to return tiles. + * + * At zoom level 0 the whole world is a square covered by a single tile, + * and the coordinates |x| and |y| are both 0 for that tile. At zoom level 1, + * the world is covered by 4 tiles with |x| and |y| being 0 or 1, and so on. + */ +@interface GMSTileLayer : NSObject + +/** + * requestTileForX:y:zoom:receiver: generates image tiles for GMSTileOverlay. + * It must be overridden by subclasses. The tile for the given |x|, |y| and + * |zoom| _must_ be later passed to |receiver|. + * + * Specify kGMSTileLayerNoTile if no tile is available for this location; or + * nil if a transient error occured and a tile may be available later. + * + * Calls to this method will be made on the main thread. See GMSSyncTileLayer + * for a base class that implements a blocking tile layer that does not run on + * your application's main thread. + */ +- (void)requestTileForX:(NSUInteger)x + y:(NSUInteger)y + zoom:(NSUInteger)zoom + receiver:(id)receiver; + +/** + * Clears the cache so that all tiles will be requested again. + */ +- (void)clearTileCache; + +/** + * The map this GMSTileOverlay is displayed on. Setting this property will add + * the layer to the map. Setting it to nil removes this layer from the map. A + * layer may be active on at most one map at any given time. + */ +@property(nonatomic, weak) GMSMapView *map; + +/** + * Higher |zIndex| value tile layers will be drawn on top of lower |zIndex| + * value tile layers and overlays. Equal values result in undefined draw + * ordering. + */ +@property(nonatomic, assign) int zIndex; + +/** + * Specifies the number of pixels (not points) that the returned tile images + * will prefer to display as. For best results, this should be the edge + * length of your custom tiles. Defaults to 256, which is the traditional + * size of Google Maps tiles. + * + * Values less than the equivalent of 128 points (e.g. 256 pixels on retina + * devices) may not perform well and are not recommended. + * + * As an example, an application developer may wish to provide retina tiles + * (512 pixel edge length) on retina devices, to keep the same number of tiles + * per view as the default value of 256 would give on a non-retina device. + */ +@property(nonatomic, assign) NSInteger tileSize; + +/** + * Specifies the opacity of the tile layer. This provides a multiplier for + * the alpha channel of tile images. + */ +@property(nonatomic, assign) float opacity; + +/** + * Specifies whether the tiles should fade in. Default YES. + */ +@property(nonatomic, assign) BOOL fadeIn; + +@end diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSUISettings.h b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSUISettings.h new file mode 100644 index 0000000..6d05c97 --- /dev/null +++ b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSUISettings.h @@ -0,0 +1,94 @@ +// +// GMSUISettings.h +// Google Maps SDK for iOS +// +// Copyright 2013 Google Inc. +// +// Usage of this SDK is subject to the Google Maps/Google Earth APIs Terms of +// Service: https://developers.google.com/maps/terms +// + +/** Settings for the user interface of a GMSMapView. */ +@interface GMSUISettings : NSObject + +/** + * Sets the preference for whether all gestures should be enabled (default) or + * disabled. This doesn't restrict users from tapping any on screen buttons to + * move the camera (e.g., compass or zoom controls), nor does it restrict + * programmatic movements and animation. + */ +- (void)setAllGesturesEnabled:(BOOL)enabled; + +/** + * Controls whether scroll gestures are enabled (default) or disabled. If + * enabled, users may drag to pan the camera. This does not limit programmatic + * movement of the camera. + */ +@property(nonatomic, assign) BOOL scrollGestures; + +/** + * Controls whether zoom gestures are enabled (default) or disabled. If + * enabled, users may double tap/two-finger tap or pinch to zoom the camera. + * This does not limit programmatic movement of the camera. + */ +@property(nonatomic, assign) BOOL zoomGestures; + +/** + * Controls whether tilt gestures are enabled (default) or disabled. If enabled, + * users may use a two-finger vertical down or up swipe to tilt the camera. This + * does not limit programmatic control of the camera's viewingAngle. + */ +@property(nonatomic, assign) BOOL tiltGestures; + +/** + * Controls whether rotate gestures are enabled (default) or disabled. If + * enabled, users may use a two-finger rotate gesture to rotate the camera. This + * does not limit programmatic control of the camera's bearing. + */ +@property(nonatomic, assign) BOOL rotateGestures; + +/** + * Controls whether gestures by users are completely consumed by the GMSMapView + * when gestures are enabled (default YES). This prevents these gestures from + * being received by parent views. + * + * When the GMSMapView is contained by a UIScrollView (or other scrollable area), + * this means that gestures on the map will not be additional consumed as scroll + * gestures. However, disabling this (set to NO) may be userful to support + * complex view hierarchies or requirements. + */ +@property(nonatomic, assign) BOOL consumesGesturesInView; + +/** + * Enables or disables the compass. The compass is an icon on the map that + * indicates the direction of north on the map. + * + * If enabled, it is only shown when the camera is rotated away from its default + * orientation (bearing of 0). When a user taps the compass, the camera orients + * itself to its default orientation and fades away shortly after. If disabled, + * the compass will never be displayed. + */ +@property(nonatomic, assign) BOOL compassButton; + +/** + * Enables or disables the My Location button. This is a button visible on the + * map that, when tapped by users, will center the map on the current user + * location. + */ +@property(nonatomic, assign) BOOL myLocationButton; + +/** + * Enables (default) or disables the indoor floor picker. If enabled, it is only + * visible when the view is focused on a building with indoor floor data. + * If disabled, the selected floor can still be controlled programatically via + * the indoorDisplay mapView property. + */ +@property(nonatomic, assign) BOOL indoorPicker; + +/** + * Controls whether rotate and zoom gestures can be performed off-center and scrolled around + * (default YES). + */ +@property(nonatomic, assign) BOOL allowScrollGesturesDuringRotateOrZoom; + +@end diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSURLTileLayer.h b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSURLTileLayer.h new file mode 100644 index 0000000..a3c6e87 --- /dev/null +++ b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSURLTileLayer.h @@ -0,0 +1,50 @@ +// +// GMSURLTileLayer.h +// Google Maps SDK for iOS +// +// Copyright 2013 Google Inc. +// +// Usage of this SDK is subject to the Google Maps/Google Earth APIs Terms of +// Service: https://developers.google.com/maps/terms +// + +#import + +@class NSURL; + +/** + * |GMSTileURLConstructor| is a block taking |x|, |y| and |zoom| + * and returning an NSURL, or nil to indicate no tile for that location. + */ +typedef NSURL *(^GMSTileURLConstructor)(NSUInteger x, NSUInteger y, NSUInteger zoom); + +/** + * GMSURLTileProvider fetches tiles based on the URLs returned from a + * GMSTileURLConstructor. For example: + *

+ *   GMSTileURLConstructor constructor = ^(NSUInteger x, NSUInteger y, NSUInteger zoom) {
+ *     NSString *URLStr =
+ *         [NSString stringWithFormat:@"https://example.com/%d/%d/%d.png", x, y, zoom];
+ *     return [NSURL URLWithString:URLStr];
+ *   };
+ *   GMSTileLayer *layer =
+ *       [GMSURLTileLayer tileLayerWithURLConstructor:constructor];
+ *   layer.userAgent = @"SDK user agent";
+ *   layer.map = map;
+ * 
+ * + * GMSURLTileProvider may not be subclassed and should only be created via its + * convenience constructor. + */ +@interface GMSURLTileLayer : GMSTileLayer + +/** Convenience constructor. |constructor| must be non-nil. */ ++ (instancetype)tileLayerWithURLConstructor:(GMSTileURLConstructor)constructor; + +/** + * Specify the user agent to describe your application. If this is nil (the + * default), the default iOS user agent is used for HTTP requests. + */ +@property(nonatomic, copy) NSString *userAgent; + +@end diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSUserAddedPlace.h b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSUserAddedPlace.h new file mode 100644 index 0000000..c9f3472 --- /dev/null +++ b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSUserAddedPlace.h @@ -0,0 +1,40 @@ +// +// GMSUserAddedPlace.h +// Google Maps SDK for iOS +// +// Copyright 2014 Google Inc. +// +// Usage of this SDK is subject to the Google Maps/Google Earth APIs Terms of +// Service: https://developers.google.com/maps/terms +// + +#import +#import + +/** + * Represents a place constructed by a user, suitable for adding to Google's collection of places. + * + * All properties must be set before passing to GMSPlacesClient.addPlace, except that either website + * _or_ phoneNumber may be nil. + */ +@interface GMSUserAddedPlace : NSObject + +/** Name of the place. */ +@property(nonatomic, copy) NSString *name; + +/** Address of the place. */ +@property(nonatomic, copy) NSString *address; + +/** Location of the place. */ +@property(nonatomic, assign) CLLocationCoordinate2D coordinate; + +/** Phone number of the place. */ +@property(nonatomic, copy) NSString *phoneNumber; + +/** List of types of the place as an array of NSStrings, like the GMSPlace.types property. */ +@property(nonatomic, copy) NSArray *types; + +/** The website for the place. */ +@property(nonatomic, copy) NSString *website; + +@end diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GoogleMaps.h b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GoogleMaps.h new file mode 100644 index 0000000..bb86c01 --- /dev/null +++ b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GoogleMaps.h @@ -0,0 +1,60 @@ +// +// GoogleMaps.h +// Google Maps SDK for iOS +// +// Copyright 2012 Google Inc. +// +// Usage of this SDK is subject to the Google Maps/Google Earth APIs Terms of +// Service: https://developers.google.com/maps/terms +// + +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Modules/module.modulemap b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Modules/module.modulemap new file mode 100644 index 0000000..c85090a --- /dev/null +++ b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Modules/module.modulemap @@ -0,0 +1 @@ +framework module GoogleMaps { umbrella header "GoogleMaps.h" export * module * { export * } } diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCacheStorage.momd/Storage.mom b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCacheStorage.momd/Storage.mom new file mode 100644 index 0000000..89db31a Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCacheStorage.momd/Storage.mom differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCacheStorage.momd/Storage.omo b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCacheStorage.momd/Storage.omo new file mode 100644 index 0000000..03b35d1 Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCacheStorage.momd/Storage.omo differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCacheStorage.momd/VersionInfo.plist b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCacheStorage.momd/VersionInfo.plist new file mode 100644 index 0000000..47b2dcd Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCacheStorage.momd/VersionInfo.plist differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/DroidSansMerged-Regular.ttf b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/DroidSansMerged-Regular.ttf new file mode 100644 index 0000000..2aca5f5 Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/DroidSansMerged-Regular.ttf differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/GMSSprites-0-1x.png b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/GMSSprites-0-1x.png new file mode 100644 index 0000000..8d7409e Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/GMSSprites-0-1x.png differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/GMSSprites-0-2x.png b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/GMSSprites-0-2x.png new file mode 100644 index 0000000..3491ab4 Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/GMSSprites-0-2x.png differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/GMSSprites-0-3x.png b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/GMSSprites-0-3x.png new file mode 100644 index 0000000..8a35660 Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/GMSSprites-0-3x.png differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/Info.plist b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/Info.plist new file mode 100644 index 0000000..761a421 Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/Info.plist differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/Roboto-Black.ttf b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/Roboto-Black.ttf new file mode 100644 index 0000000..cb905bc Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/Roboto-Black.ttf differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/Roboto-BlackItalic.ttf b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/Roboto-BlackItalic.ttf new file mode 100644 index 0000000..3ebdc7d Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/Roboto-BlackItalic.ttf differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/Roboto-Bold.ttf b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/Roboto-Bold.ttf new file mode 100644 index 0000000..68822ca Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/Roboto-Bold.ttf differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/Roboto-BoldItalic.ttf b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/Roboto-BoldItalic.ttf new file mode 100644 index 0000000..aebf8eb Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/Roboto-BoldItalic.ttf differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/Roboto-Italic.ttf b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/Roboto-Italic.ttf new file mode 100644 index 0000000..2041cbc Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/Roboto-Italic.ttf differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/Roboto-Light.ttf b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/Roboto-Light.ttf new file mode 100644 index 0000000..aa45340 Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/Roboto-Light.ttf differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/Roboto-LightItalic.ttf b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/Roboto-LightItalic.ttf new file mode 100644 index 0000000..a85444f Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/Roboto-LightItalic.ttf differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/Roboto-Medium.ttf b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/Roboto-Medium.ttf new file mode 100644 index 0000000..a3c1a1f Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/Roboto-Medium.ttf differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/Roboto-MediumItalic.ttf b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/Roboto-MediumItalic.ttf new file mode 100644 index 0000000..b828205 Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/Roboto-MediumItalic.ttf differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/Roboto-Regular.ttf b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/Roboto-Regular.ttf new file mode 100644 index 0000000..0e58508 Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/Roboto-Regular.ttf differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/Roboto-Thin.ttf b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/Roboto-Thin.ttf new file mode 100644 index 0000000..8779333 Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/Roboto-Thin.ttf differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/Roboto-ThinItalic.ttf b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/Roboto-ThinItalic.ttf new file mode 100644 index 0000000..b79cb26 Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/Roboto-ThinItalic.ttf differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/RobotoCondensed-Italic.ttf b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/RobotoCondensed-Italic.ttf new file mode 100644 index 0000000..d2b611f Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/RobotoCondensed-Italic.ttf differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/RobotoCondensed-Regular.ttf b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/RobotoCondensed-Regular.ttf new file mode 100644 index 0000000..b9fc49c Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/RobotoCondensed-Regular.ttf differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/Siemreap.ttf b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/Siemreap.ttf new file mode 100644 index 0000000..a2c8dff Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/Siemreap.ttf differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/Tharlon-Regular.ttf b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/Tharlon-Regular.ttf new file mode 100644 index 0000000..4717d70 Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/Tharlon-Regular.ttf differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/ar.lproj/GMSCore.strings b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/ar.lproj/GMSCore.strings new file mode 100644 index 0000000..de9f9e8 Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/ar.lproj/GMSCore.strings differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/button_background.png b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/button_background.png new file mode 100644 index 0000000..847575a Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/button_background.png differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/button_background@2x.png b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/button_background@2x.png new file mode 100644 index 0000000..84e76a3 Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/button_background@2x.png differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/button_background@3x.png b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/button_background@3x.png new file mode 100644 index 0000000..b89372f Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/button_background@3x.png differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/button_compass.png b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/button_compass.png new file mode 100644 index 0000000..a0b07bb Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/button_compass.png differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/button_compass@2x.png b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/button_compass@2x.png new file mode 100644 index 0000000..c03e1e9 Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/button_compass@2x.png differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/button_my_location.png b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/button_my_location.png new file mode 100644 index 0000000..e32568d Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/button_my_location.png differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/button_my_location@2x.png b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/button_my_location@2x.png new file mode 100644 index 0000000..c5465b7 Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/button_my_location@2x.png differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/ca.lproj/GMSCore.strings b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/ca.lproj/GMSCore.strings new file mode 100644 index 0000000..83af8e3 Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/ca.lproj/GMSCore.strings differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/cs.lproj/GMSCore.strings b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/cs.lproj/GMSCore.strings new file mode 100644 index 0000000..aacf12c Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/cs.lproj/GMSCore.strings differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/da.lproj/GMSCore.strings b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/da.lproj/GMSCore.strings new file mode 100644 index 0000000..d9d96ac Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/da.lproj/GMSCore.strings differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/dav_one_way_16_256.png b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/dav_one_way_16_256.png new file mode 100644 index 0000000..cb77f83 Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/dav_one_way_16_256.png differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/de.lproj/GMSCore.strings b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/de.lproj/GMSCore.strings new file mode 100644 index 0000000..ffa8a58 Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/de.lproj/GMSCore.strings differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/el.lproj/GMSCore.strings b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/el.lproj/GMSCore.strings new file mode 100644 index 0000000..457e994 Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/el.lproj/GMSCore.strings differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/en.lproj/GMSCore.strings b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/en.lproj/GMSCore.strings new file mode 100644 index 0000000..4ee0314 Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/en.lproj/GMSCore.strings differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/en_GB.lproj/GMSCore.strings b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/en_GB.lproj/GMSCore.strings new file mode 100644 index 0000000..91e4ccb Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/en_GB.lproj/GMSCore.strings differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/es.lproj/GMSCore.strings b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/es.lproj/GMSCore.strings new file mode 100644 index 0000000..50636cb Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/es.lproj/GMSCore.strings differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/fi.lproj/GMSCore.strings b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/fi.lproj/GMSCore.strings new file mode 100644 index 0000000..bb6c09a Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/fi.lproj/GMSCore.strings differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/fr.lproj/GMSCore.strings b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/fr.lproj/GMSCore.strings new file mode 100644 index 0000000..f8b7c87 Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/fr.lproj/GMSCore.strings differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/he.lproj/GMSCore.strings b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/he.lproj/GMSCore.strings new file mode 100644 index 0000000..1288e8a Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/he.lproj/GMSCore.strings differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/hr.lproj/GMSCore.strings b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/hr.lproj/GMSCore.strings new file mode 100644 index 0000000..3d840fa Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/hr.lproj/GMSCore.strings differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/hu.lproj/GMSCore.strings b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/hu.lproj/GMSCore.strings new file mode 100644 index 0000000..9c6b00b Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/hu.lproj/GMSCore.strings differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/ic_compass_needle.png b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/ic_compass_needle.png new file mode 100644 index 0000000..6e0663e Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/ic_compass_needle.png differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/ic_compass_needle@2x.png b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/ic_compass_needle@2x.png new file mode 100644 index 0000000..f1d5caf Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/ic_compass_needle@2x.png differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/ic_qu_direction_mylocation.png b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/ic_qu_direction_mylocation.png new file mode 100644 index 0000000..4bd8c8f Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/ic_qu_direction_mylocation.png differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/ic_qu_direction_mylocation@2x.png b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/ic_qu_direction_mylocation@2x.png new file mode 100644 index 0000000..b2cf321 Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/ic_qu_direction_mylocation@2x.png differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/ic_qu_direction_mylocation@3x.png b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/ic_qu_direction_mylocation@3x.png new file mode 100644 index 0000000..91cf55f Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/ic_qu_direction_mylocation@3x.png differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/id.lproj/GMSCore.strings b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/id.lproj/GMSCore.strings new file mode 100644 index 0000000..61faea9 Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/id.lproj/GMSCore.strings differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/it.lproj/GMSCore.strings b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/it.lproj/GMSCore.strings new file mode 100644 index 0000000..0afe1f2 Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/it.lproj/GMSCore.strings differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/ja.lproj/GMSCore.strings b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/ja.lproj/GMSCore.strings new file mode 100644 index 0000000..54a532b Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/ja.lproj/GMSCore.strings differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/ko.lproj/GMSCore.strings b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/ko.lproj/GMSCore.strings new file mode 100644 index 0000000..9f4c41c Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/ko.lproj/GMSCore.strings differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/ms.lproj/GMSCore.strings b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/ms.lproj/GMSCore.strings new file mode 100644 index 0000000..3eee646 Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/ms.lproj/GMSCore.strings differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/nl.lproj/GMSCore.strings b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/nl.lproj/GMSCore.strings new file mode 100644 index 0000000..31a4197 Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/nl.lproj/GMSCore.strings differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/no.lproj/GMSCore.strings b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/no.lproj/GMSCore.strings new file mode 100644 index 0000000..dad08a4 Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/no.lproj/GMSCore.strings differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/pl.lproj/GMSCore.strings b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/pl.lproj/GMSCore.strings new file mode 100644 index 0000000..f59c162 Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/pl.lproj/GMSCore.strings differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/polyline_colors_texture.png b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/polyline_colors_texture.png new file mode 100644 index 0000000..badf109 Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/polyline_colors_texture.png differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/pt.lproj/GMSCore.strings b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/pt.lproj/GMSCore.strings new file mode 100644 index 0000000..d08bfc1 Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/pt.lproj/GMSCore.strings differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/pt_PT.lproj/GMSCore.strings b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/pt_PT.lproj/GMSCore.strings new file mode 100644 index 0000000..f98aac2 Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/pt_PT.lproj/GMSCore.strings differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/ro.lproj/GMSCore.strings b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/ro.lproj/GMSCore.strings new file mode 100644 index 0000000..576d222 Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/ro.lproj/GMSCore.strings differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/road_1-1.png b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/road_1-1.png new file mode 100644 index 0000000..46b0843 Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/road_1-1.png differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/road_128-32.png b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/road_128-32.png new file mode 100644 index 0000000..357d1df Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/road_128-32.png differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/road_16-4.png b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/road_16-4.png new file mode 100644 index 0000000..35f58cf Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/road_16-4.png differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/road_2-1.png b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/road_2-1.png new file mode 100644 index 0000000..df77f65 Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/road_2-1.png differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/road_256-64.png b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/road_256-64.png new file mode 100644 index 0000000..5162343 Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/road_256-64.png differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/road_32-8.png b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/road_32-8.png new file mode 100644 index 0000000..ed0424b Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/road_32-8.png differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/road_4-1.png b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/road_4-1.png new file mode 100644 index 0000000..a44a743 Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/road_4-1.png differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/road_64-16.png b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/road_64-16.png new file mode 100644 index 0000000..46915dc Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/road_64-16.png differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/road_8-2.png b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/road_8-2.png new file mode 100644 index 0000000..be12717 Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/road_8-2.png differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/ru.lproj/GMSCore.strings b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/ru.lproj/GMSCore.strings new file mode 100644 index 0000000..c488955 Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/ru.lproj/GMSCore.strings differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/sk.lproj/GMSCore.strings b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/sk.lproj/GMSCore.strings new file mode 100644 index 0000000..3188adf Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/sk.lproj/GMSCore.strings differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/sv.lproj/GMSCore.strings b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/sv.lproj/GMSCore.strings new file mode 100644 index 0000000..530d064 Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/sv.lproj/GMSCore.strings differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/th.lproj/GMSCore.strings b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/th.lproj/GMSCore.strings new file mode 100644 index 0000000..b544aa9 Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/th.lproj/GMSCore.strings differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/tr.lproj/GMSCore.strings b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/tr.lproj/GMSCore.strings new file mode 100644 index 0000000..2878e9a Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/tr.lproj/GMSCore.strings differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/uk.lproj/GMSCore.strings b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/uk.lproj/GMSCore.strings new file mode 100644 index 0000000..249e3d6 Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/uk.lproj/GMSCore.strings differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/vi.lproj/GMSCore.strings b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/vi.lproj/GMSCore.strings new file mode 100644 index 0000000..6539316 Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/vi.lproj/GMSCore.strings differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/watermark_dark.png b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/watermark_dark.png new file mode 100644 index 0000000..be3a8ab Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/watermark_dark.png differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/watermark_dark@2x.png b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/watermark_dark@2x.png new file mode 100644 index 0000000..4bae5d5 Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/watermark_dark@2x.png differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/watermark_dark@3x.png b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/watermark_dark@3x.png new file mode 100644 index 0000000..ef7290b Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/watermark_dark@3x.png differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/watermark_light.png b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/watermark_light.png new file mode 100644 index 0000000..10624db Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/watermark_light.png differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/watermark_light@2x.png b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/watermark_light@2x.png new file mode 100644 index 0000000..36112a0 Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/watermark_light@2x.png differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/watermark_light@3x.png b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/watermark_light@3x.png new file mode 100644 index 0000000..6ad6233 Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/watermark_light@3x.png differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/zh_CN.lproj/GMSCore.strings b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/zh_CN.lproj/GMSCore.strings new file mode 100644 index 0000000..dd4b0a5 Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/zh_CN.lproj/GMSCore.strings differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/zh_TW.lproj/GMSCore.strings b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/zh_TW.lproj/GMSCore.strings new file mode 100644 index 0000000..6ec7c70 Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/GMSCoreResources.bundle/zh_TW.lproj/GMSCore.strings differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/Info.plist b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/Info.plist new file mode 100644 index 0000000..be46cbe Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/Info.plist differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/active.png b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/active.png new file mode 100644 index 0000000..cbcf301 Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/active.png differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/active@2x.png b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/active@2x.png new file mode 100644 index 0000000..5f8306a Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/active@2x.png differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/active@3x.png b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/active@3x.png new file mode 100644 index 0000000..170c60f Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/active@3x.png differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/active_grouped.png b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/active_grouped.png new file mode 100644 index 0000000..1e1bcf6 Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/active_grouped.png differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/active_grouped@2x.png b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/active_grouped@2x.png new file mode 100644 index 0000000..143e144 Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/active_grouped@2x.png differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/active_grouped@3x.png b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/active_grouped@3x.png new file mode 100644 index 0000000..1205603 Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/active_grouped@3x.png differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/back.png b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/back.png new file mode 100644 index 0000000..2765dbc Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/back.png differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/back@2x.png b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/back@2x.png new file mode 100644 index 0000000..a9fcb27 Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/back@2x.png differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/back@3x.png b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/back@3x.png new file mode 100644 index 0000000..add6f20 Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/back@3x.png differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/bubble_left.png b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/bubble_left.png new file mode 100644 index 0000000..0f8db09 Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/bubble_left.png differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/bubble_left@2x.png b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/bubble_left@2x.png new file mode 100644 index 0000000..8ece32c Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/bubble_left@2x.png differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/bubble_left@3x.png b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/bubble_left@3x.png new file mode 100644 index 0000000..dfdc21a Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/bubble_left@3x.png differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/bubble_right.png b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/bubble_right.png new file mode 100644 index 0000000..4ed47e4 Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/bubble_right.png differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/bubble_right@2x.png b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/bubble_right@2x.png new file mode 100644 index 0000000..475f4b8 Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/bubble_right@2x.png differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/bubble_right@3x.png b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/bubble_right@3x.png new file mode 100644 index 0000000..fc7e633 Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/bubble_right@3x.png differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/card_bg.png b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/card_bg.png new file mode 100644 index 0000000..2ae75f6 Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/card_bg.png differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/card_bg@2x.png b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/card_bg@2x.png new file mode 100644 index 0000000..3638007 Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/card_bg@2x.png differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/card_bg@3x.png b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/card_bg@3x.png new file mode 100644 index 0000000..8d7ae8f Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/card_bg@3x.png differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/close.png b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/close.png new file mode 100644 index 0000000..9e693f1 Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/close.png differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/close@2x.png b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/close@2x.png new file mode 100644 index 0000000..8b9caea Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/close@2x.png differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/close@3x.png b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/close@3x.png new file mode 100644 index 0000000..6edea38 Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/close@3x.png differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/default_marker.png b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/default_marker.png new file mode 100644 index 0000000..f51c3a4 Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/default_marker.png differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/default_marker@2x.png b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/default_marker@2x.png new file mode 100644 index 0000000..59dbd92 Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/default_marker@2x.png differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/default_marker@3x.png b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/default_marker@3x.png new file mode 100644 index 0000000..829ea5f Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/default_marker@3x.png differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/en.lproj/InfoPlist.strings b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/en.lproj/InfoPlist.strings new file mode 100644 index 0000000..3967e06 Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/en.lproj/InfoPlist.strings differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/place_picker_nav_back.png b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/place_picker_nav_back.png new file mode 100644 index 0000000..4c72bcf Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/place_picker_nav_back.png differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/place_picker_nav_back@2x.png b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/place_picker_nav_back@2x.png new file mode 100644 index 0000000..95bc759 Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/place_picker_nav_back@2x.png differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/place_picker_search_icon.png b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/place_picker_search_icon.png new file mode 100644 index 0000000..7e6193a Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/place_picker_search_icon.png differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/place_picker_search_icon@2x.png b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/place_picker_search_icon@2x.png new file mode 100644 index 0000000..61e1e74 Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/place_picker_search_icon@2x.png differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/red_icons.png b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/red_icons.png new file mode 100644 index 0000000..c6a7bec Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/red_icons.png differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/red_icons@2x.png b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/red_icons@2x.png new file mode 100644 index 0000000..f0a5e9f Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/red_icons@2x.png differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/red_icons@3x.png b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/red_icons@3x.png new file mode 100644 index 0000000..02f0826 Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/red_icons@3x.png differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/white_icons.png b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/white_icons.png new file mode 100644 index 0000000..49b4e9d Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/white_icons.png differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/white_icons@2x.png b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/white_icons@2x.png new file mode 100644 index 0000000..a42707e Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/white_icons@2x.png differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/white_icons@3x.png b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/white_icons@3x.png new file mode 100644 index 0000000..5838eb0 Binary files /dev/null and b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle/white_icons@3x.png differ diff --git a/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/Current b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/Current new file mode 120000 index 0000000..8c7e5a6 --- /dev/null +++ b/Pods/GoogleMaps/Frameworks/GoogleMaps.framework/Versions/Current @@ -0,0 +1 @@ +A \ No newline at end of file diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/GoogleMaps.framework b/Pods/GoogleMaps/GoogleMapsSDKDemos/GoogleMaps.framework new file mode 120000 index 0000000..4e52fac --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/GoogleMaps.framework @@ -0,0 +1 @@ +../Frameworks/GoogleMaps.framework \ No newline at end of file diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/README.GoogleMapsSDKDemos b/Pods/GoogleMaps/GoogleMapsSDKDemos/README.GoogleMapsSDKDemos new file mode 100644 index 0000000..e39aa06 --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/README.GoogleMapsSDKDemos @@ -0,0 +1,22 @@ +GoogleMapsSDKDemos contains a demo application showcasing various features of +the Google Maps SDK for iOS. + +Before starting, please note that these demos are directed towards a technical +audience. You'll also need Xcode 6.3 or later, with the iOS SDK 7.0 or later. + +If you're new to the SDK, please read the Introduction section of the Google +Maps SDK for iOS documentation- + https://developers.google.com/maps/documentation/ios + +Once you've read the Introduction page, follow the first couple of steps on the +"Getting Started" page. Specifically; + + * Obtain an API key for the demo application, and specify the bundle ID of + this demo application as an an 'allowed iOS app'. By default, the bundle ID + is "com.example.SDKDemos". + + * Open the project in Xcode, and update `SDKDemoAPIKey.h` with this key. + +If you'd like to add a new sample, add a new subclass of `ViewController` and +add it to the samples definitions inside the `Samples.m`. + diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos.gyp b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos.gyp new file mode 100644 index 0000000..fdc89bc --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos.gyp @@ -0,0 +1,60 @@ +{ + 'xcode_settings': { + 'SDKROOT': 'iphoneos', + }, + 'targets': [ + { + 'target_name': 'SDKDemos', + 'type': 'executable', + 'mac_bundle': 1, + 'mac_framework_dirs': [ + '$(SRCROOT)', + ], + 'link_settings': { + 'mac_bundle_resources': [ + '"; }; + 031103FAE4E394EA78895993 /* SDKDemoMasterViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDKDemoMasterViewController.m; sourceTree = ""; }; + 0372FAEB924D0ADD012FBDFE /* Default@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default@2x.png"; sourceTree = ""; }; + 0416087FE83DCD914CF69FA9 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; + 043F8041B5649C26BCE75231 /* Samples.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Samples.m; sourceTree = ""; }; + 09F0DD5C27A815E1A9720747 /* TrafficMapViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TrafficMapViewController.h; sourceTree = ""; }; + 0B6999063F311237F673B8B0 /* IndoorViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IndoorViewController.m; sourceTree = ""; }; + 0BA108F4D0C3BDA34CE54180 /* GestureControlViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GestureControlViewController.m; sourceTree = ""; }; + 0F33C1C90D61AD0E2B502215 /* sdkdemos_icon-72@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "sdkdemos_icon-72@2x.png"; sourceTree = ""; }; + 124B199908A64B1EE958F3CA /* x29@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "x29@2x.png"; sourceTree = ""; }; + 13CBFFCFE30583D29D77B5A1 /* MarkerInfoWindowViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MarkerInfoWindowViewController.h; sourceTree = ""; }; + 14532E524E38739F32328ECE /* Samples+Places.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Samples+Places.h"; sourceTree = ""; }; + 14A1E50F98F1EA56590AA120 /* step3@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "step3@2x.png"; sourceTree = ""; }; + 15F93E8BE938118367B428AA /* MarkersViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MarkersViewController.h; sourceTree = ""; }; + 193951C11D1549E7701FFC40 /* libc++.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = "libc++.dylib"; path = "usr/lib/libc++.dylib"; sourceTree = SDKROOT; }; + 1A597E83DFFF77F1EBD76B64 /* museum-exhibits.json */ = {isa = PBXFileReference; lastKnownFileType = text; path = "museum-exhibits.json"; sourceTree = ""; }; + 1BA8114B0A4CDC672F1CBD6F /* GeocoderViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeocoderViewController.h; sourceTree = ""; }; + 1F1D873627D847B5C1B099FC /* MarkerEventsViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MarkerEventsViewController.m; sourceTree = ""; }; + 2AB2A95CCD24024671158AD9 /* PanoramaViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PanoramaViewController.h; sourceTree = ""; }; + 2E95ACF5DD497E15A0B746DF /* glow-marker.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "glow-marker.png"; sourceTree = ""; }; + 31DE8BA62A492FBC67E923AD /* sdkdemos_icon-72.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "sdkdemos_icon-72.png"; sourceTree = ""; }; + 31F229C07CCFB0CFEBD70F68 /* MapLayerViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MapLayerViewController.m; sourceTree = ""; }; + 3401A5B1795F7B7056A7F491 /* arrow.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = arrow.png; sourceTree = ""; }; + 3449C03C22DABB720D80FF72 /* GestureControlViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GestureControlViewController.h; sourceTree = ""; }; + 359EF8FC1D5600228CFFBF4D /* step6.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = step6.png; sourceTree = ""; }; + 3628691A5936DDD1821A622B /* step7.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = step7.png; sourceTree = ""; }; + 394AF35F597FB89E9D6A1E3D /* MapZoomViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MapZoomViewController.h; sourceTree = ""; }; + 3AAAD985B0FF3AF55E964A33 /* IndoorMuseumNavigationViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IndoorMuseumNavigationViewController.m; sourceTree = ""; }; + 3BD92F5F6AB10EDD9098A9DC /* GeocoderViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GeocoderViewController.m; sourceTree = ""; }; + 3C1A74AB0EFA8C78AF23E564 /* step5.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = step5.png; sourceTree = ""; }; + 3F1ABBF9B2E96BC488485119 /* track.json */ = {isa = PBXFileReference; lastKnownFileType = text; path = track.json; sourceTree = ""; }; + 4152CBF14080E0C84DFD6613 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; }; + 425802FD822D22CC110119BA /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; + 429F95111FD1F8B8A1C16865 /* PolylinesViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PolylinesViewController.m; sourceTree = ""; }; + 45580B3C558B48DD3359F2A1 /* MapZoomViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MapZoomViewController.m; sourceTree = ""; }; + 460EBDFBDFFE13DB517214A5 /* BasicMapViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BasicMapViewController.h; sourceTree = ""; }; + 46FF553F45838251496245F9 /* arrow@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "arrow@2x.png"; sourceTree = ""; }; + 487E4999CFF757EA18C569D8 /* x29.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = x29.png; sourceTree = ""; }; + 48C5F2798147CFFA14B5B7DD /* SDKDemoPlacePickerViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDKDemoPlacePickerViewController.h; sourceTree = ""; }; + 4BA4E139EA9FAA0D6A639CE6 /* BasicMapViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BasicMapViewController.m; sourceTree = ""; }; + 4C29D1A0DA47D1691C6CE0A5 /* argentina-large.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "argentina-large.png"; sourceTree = ""; }; + 4C3CBB9D63F29447E8C3C06F /* step2@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "step2@2x.png"; sourceTree = ""; }; + 4D35CE548040C1EF3B8BD581 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; + 4F353004786E58271D76683E /* Default-Landscape~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-Landscape~ipad.png"; sourceTree = ""; }; + 54743FFF10003AA647D1654F /* australia-large.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "australia-large.png"; sourceTree = ""; }; + 550E6B03BFE321336D066223 /* spitfire@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "spitfire@2x.png"; sourceTree = ""; }; + 58B0EFEC1C69A989B6E84744 /* h1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = h1.png; sourceTree = ""; }; + 5977F6DB8B9BD6609BE664B0 /* TileLayerViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TileLayerViewController.h; sourceTree = ""; }; + 59940AD9F86687DEA94EDE8C /* CameraViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CameraViewController.h; sourceTree = ""; }; + 5AA08AB86BAE0FBBB8B3705F /* boat.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = boat.png; sourceTree = ""; }; + 5EC5186C29703467E4C2ED80 /* SDKDemoAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDKDemoAppDelegate.m; sourceTree = ""; }; + 5F3C1FEA265C2BC44CFFB4BD /* MapTypesViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MapTypesViewController.m; sourceTree = ""; }; + 62CBE24F5F8C7DF19AE8452C /* step4@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "step4@2x.png"; sourceTree = ""; }; + 63B21B38E81405568CD36449 /* AnimatedCurrentLocationViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AnimatedCurrentLocationViewController.h; sourceTree = ""; }; + 64888C52E2E272FEFE7C18AA /* StructuredGeocoderViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = StructuredGeocoderViewController.m; sourceTree = ""; }; + 656D0083D388D030EA0C9E3E /* SDKDemos.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SDKDemos.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 6571C6FD38FB80E9657C6CF4 /* PolylinesViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PolylinesViewController.h; sourceTree = ""; }; + 6A37ED9FA16A22EFC586E32E /* MyLocationViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MyLocationViewController.m; sourceTree = ""; }; + 6D2F332D6F2FB20FE11DFB6E /* step3.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = step3.png; sourceTree = ""; }; + 6DEE18F2AE053B9A1DB19C5C /* TileLayerViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TileLayerViewController.m; sourceTree = ""; }; + 72FF2F70BA1B0073BE1F375F /* newark_nj_1922.jpg */ = {isa = PBXFileReference; lastKnownFileType = text; path = newark_nj_1922.jpg; sourceTree = ""; }; + 735DFE797020C7F09B21F773 /* CustomIndoorViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CustomIndoorViewController.h; sourceTree = ""; }; + 7385EE81D06D3C1BD826B7C5 /* step5@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "step5@2x.png"; sourceTree = ""; }; + 74A9950FBE5A377D1EBB2230 /* SDKDemoMasterViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDKDemoMasterViewController.h; sourceTree = ""; }; + 74F5EF3ED006A948BCC2BF82 /* libobjc.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libobjc.dylib; path = usr/lib/libobjc.dylib; sourceTree = SDKROOT; }; + 75E000124A1962A304CEAAB8 /* aeroplane.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = aeroplane.png; sourceTree = ""; }; + 778A178288F1E9593A03C6DB /* Samples.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Samples.h; sourceTree = ""; }; + 778FAE1359A6570015F495EA /* GroundOverlayViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GroundOverlayViewController.h; sourceTree = ""; }; + 77EA8532CD15A6B5E800415E /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = ""; }; + 78C6F7D665C6DD4328894967 /* TrafficMapViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TrafficMapViewController.m; sourceTree = ""; }; + 799CC7F35C34DAA014613DDF /* aeroplane@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "aeroplane@2x.png"; sourceTree = ""; }; + 79A9E14215E011A6DFD2B0BA /* GradientPolylinesViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GradientPolylinesViewController.h; sourceTree = ""; }; + 7B47995B2A94F831E8B7DD0F /* GLKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GLKit.framework; path = System/Library/Frameworks/GLKit.framework; sourceTree = SDKROOT; }; + 7B4AF795B18672B900DE3568 /* MarkerEventsViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MarkerEventsViewController.h; sourceTree = ""; }; + 7BBAEFAF2820EDE4EBA5D943 /* OpenGLES.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGLES.framework; path = System/Library/Frameworks/OpenGLES.framework; sourceTree = SDKROOT; }; + 7BFD80C8485C48F2C90C85A8 /* GradientPolylinesViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GradientPolylinesViewController.m; sourceTree = ""; }; + 7EC4132AB51E1500FF16E4C5 /* voyager.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = voyager.png; sourceTree = ""; }; + 81B8039817FFB9A398E1158B /* DoubleMapViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DoubleMapViewController.h; sourceTree = ""; }; + 837C86EA9AC87A3A5EA16145 /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; }; + 842A2FB43838968D313B1783 /* Default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Default.png; sourceTree = ""; }; + 85109740028667AB1646AC2D /* glow-marker@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "glow-marker@2x.png"; sourceTree = ""; }; + 85288BF143D609A7145A7846 /* popup_santa.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = popup_santa.png; sourceTree = ""; }; + 88F50C2BAD0B000697EBECCE /* boat@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "boat@2x.png"; sourceTree = ""; }; + 8B3EA327A271CA6A64D117A6 /* FitBoundsViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FitBoundsViewController.m; sourceTree = ""; }; + 8EB73A280D8FE0A1D2C054C8 /* bulgaria-large.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "bulgaria-large.png"; sourceTree = ""; }; + 8F59372BD761533A2A6B470A /* GoogleMaps.bundle */ = {isa = PBXFileReference; lastKnownFileType = wrapper.cfbundle; path = GoogleMaps.bundle; sourceTree = ""; }; + 8F6ED0C99E84A5FE46148309 /* libicucore.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libicucore.dylib; path = usr/lib/libicucore.dylib; sourceTree = SDKROOT; }; + 90258FFF395A5E25CCEC3AB0 /* PolygonsViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PolygonsViewController.m; sourceTree = ""; }; + 9285758C5E07413BA20C8840 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; + 933F14F944559A5D5538023D /* AnimatedCurrentLocationViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AnimatedCurrentLocationViewController.m; sourceTree = ""; }; + 959C749EEFBCC25DCDCC1416 /* Launch.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = Launch.xib; sourceTree = ""; }; + 97284C2589969381B1F2BF65 /* botswana.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = botswana.png; sourceTree = ""; }; + 9820B8516BCB7CD9A6553720 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; }; + 989BBAF7DF1CD21CA2F9CC0E /* FixedPanoramaViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FixedPanoramaViewController.h; sourceTree = ""; }; + 98A5F219881F5A5612905ABC /* step4.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = step4.png; sourceTree = ""; }; + 9A2729CB24AF1A2D245CD886 /* CameraViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CameraViewController.m; sourceTree = ""; }; + 9AB08565AAF1A341BC7D2A61 /* MarkerLayerViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MarkerLayerViewController.m; sourceTree = ""; }; + 9C2D5258F1365BCD57029138 /* MarkersViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MarkersViewController.m; sourceTree = ""; }; + A38AE667ACADB5627CF67973 /* CoreLocation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreLocation.framework; path = System/Library/Frameworks/CoreLocation.framework; sourceTree = SDKROOT; }; + A48DE20E9EF0EFE5F9656B51 /* SDKDemoAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDKDemoAppDelegate.h; sourceTree = ""; }; + A56AF9AA60B75EF16CE3EF8C /* Default-Portrait~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-Portrait~ipad.png"; sourceTree = ""; }; + A578CA16809EBB3047B3C573 /* DoubleMapViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DoubleMapViewController.m; sourceTree = ""; }; + A849C0D00CED5DEF33AC6844 /* MapLayerViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MapLayerViewController.h; sourceTree = ""; }; + AAA8B2B19FA46102744D14EF /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; }; + AB330C8620876E40BEC85968 /* voyager@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "voyager@2x.png"; sourceTree = ""; }; + ABAA14F70E24A8E44326BBAE /* FixedPanoramaViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FixedPanoramaViewController.m; sourceTree = ""; }; + AC4F4FF0F15305FE7DB327D5 /* MyLocationViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MyLocationViewController.h; sourceTree = ""; }; + ADB6F5B2F34C4461E2AFF686 /* CustomMarkersViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CustomMarkersViewController.h; sourceTree = ""; }; + ADDE981D53FECD067A463663 /* CoreBluetooth.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreBluetooth.framework; path = System/Library/Frameworks/CoreBluetooth.framework; sourceTree = SDKROOT; }; + B1FA4EC4A89767E10B655CB0 /* MarkerLayerViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MarkerLayerViewController.h; sourceTree = ""; }; + B247AC68273A6B9F29ED6CDC /* ImageIO.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ImageIO.framework; path = System/Library/Frameworks/ImageIO.framework; sourceTree = SDKROOT; }; + B6D2F25F8F4B1159C707B4A2 /* IndoorViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IndoorViewController.h; sourceTree = ""; }; + B8B2C467E3382D3E31EA92E1 /* SDKDemoPlacePickerViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDKDemoPlacePickerViewController.m; sourceTree = ""; }; + BA7783E4FDFA7455B4EF6174 /* PolygonsViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PolygonsViewController.h; sourceTree = ""; }; + BAF511F09C737A22E0A76E59 /* bulgaria.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = bulgaria.png; sourceTree = ""; }; + BD36A58B321268BB8E267874 /* CustomMarkersViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CustomMarkersViewController.m; sourceTree = ""; }; + BD7A194DAB9B544294D7A2D0 /* GroundOverlayViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GroundOverlayViewController.m; sourceTree = ""; }; + C07CD02A92489C92FC822C3A /* SDKDemoAPIKey.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDKDemoAPIKey.h; sourceTree = ""; }; + C4D94F429262C3A09166D73F /* australia-large@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "australia-large@2x.png"; sourceTree = ""; }; + C7AB12C7756274D40E649762 /* step7@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "step7@2x.png"; sourceTree = ""; }; + C9926C6844E111CB23EF2E80 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + CD99D73AD66B03243C670572 /* sdkdemos_icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = sdkdemos_icon.png; sourceTree = ""; }; + D03EB3995F5EF92504D8E44F /* Default-Portrait@2x~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-Portrait@2x~ipad.png"; sourceTree = ""; }; + D05C1274204C92F13ABD8599 /* step6@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "step6@2x.png"; sourceTree = ""; }; + D1B2675ECA97CB1F5D0F5F88 /* MapTypesViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MapTypesViewController.h; sourceTree = ""; }; + D2325AC9E493AAC86F87681E /* GoogleMaps.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = GoogleMaps.framework; sourceTree = ""; }; + D2DFE1BF52A3A8AFFF379322 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; }; + D619B3D989A533F358F1D077 /* botswana-large.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "botswana-large.png"; sourceTree = ""; }; + D6A64F2A232BF392091BFB79 /* Accelerate.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Accelerate.framework; path = System/Library/Frameworks/Accelerate.framework; sourceTree = SDKROOT; }; + D7B0E6B7E378BF2301E42C6A /* StructuredGeocoderViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = StructuredGeocoderViewController.h; sourceTree = ""; }; + D81C6119C4C7DE07FB42F86D /* popup_santa@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "popup_santa@2x.png"; sourceTree = ""; }; + D83F65E0A08406E055A906B0 /* step2.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = step2.png; sourceTree = ""; }; + D8C04CF121E2CAC61D549125 /* CoreText.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreText.framework; path = System/Library/Frameworks/CoreText.framework; sourceTree = SDKROOT; }; + DABC6731995E50EBF60E82DA /* VisibleRegionViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = VisibleRegionViewController.m; sourceTree = ""; }; + DBBB2837C3A8ADB3D5191304 /* PanoramaViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PanoramaViewController.m; sourceTree = ""; }; + DC53293C94A672B4C62AD559 /* step1@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "step1@2x.png"; sourceTree = ""; }; + DC8661CA82A046ED2AF5B71F /* MarkerInfoWindowViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MarkerInfoWindowViewController.m; sourceTree = ""; }; + E0D4EAD84FB1F606F6016E0B /* VisibleRegionViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = VisibleRegionViewController.h; sourceTree = ""; }; + E4B1CC9979AFE466B59A9AC4 /* IndoorMuseumNavigationViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IndoorMuseumNavigationViewController.h; sourceTree = ""; }; + E8CF929DF33D172F36F845E3 /* step8.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = step8.png; sourceTree = ""; }; + EA55E63E3ECB92756B8A8854 /* australia.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = australia.png; sourceTree = ""; }; + EB1CD2C01411A35969C872BA /* CustomIndoorViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CustomIndoorViewController.m; sourceTree = ""; }; + EBDAAD248E528C9D828A2878 /* argentina.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = argentina.png; sourceTree = ""; }; + EBDF69733C905396E3568053 /* Samples+Places.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "Samples+Places.m"; sourceTree = ""; }; + EF3CF28401B594ADE426E656 /* h1@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "h1@2x.png"; sourceTree = ""; }; + FA940308742FE4A8E2ACB6DB /* Default-Landscape@2x~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-Landscape@2x~ipad.png"; sourceTree = ""; }; + FAF66F7D7BC732C1A5A896B0 /* SDKDemos.gyp */ = {isa = PBXFileReference; explicitFileType = sourcecode; path = SDKDemos.gyp; sourceTree = ""; }; + FCCC58E7443B387046306EEF /* step8@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "step8@2x.png"; sourceTree = ""; }; + FD181A33530788C065AA2D90 /* sdkdemos_icon@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "sdkdemos_icon@2x.png"; sourceTree = ""; }; + FD40AB7623BD1C9A81EA9239 /* FitBoundsViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FitBoundsViewController.h; sourceTree = ""; }; + FE2B3D4C04A8916BC8027A72 /* spitfire.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = spitfire.png; sourceTree = ""; }; + FE7C2DA207359F759D081156 /* step1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = step1.png; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 9F427D7DE56744A968901ED9 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + FF3DA502EBB043CA9CBCC44C /* GoogleMaps.framework in Frameworks */, + 939D9DD972B3C9CEF6268682 /* libobjc.dylib in Frameworks */, + 7151879999E96F2B5F8EC9AD /* CoreFoundation.framework in Frameworks */, + 541DAAB4C469032E7585D5D6 /* Foundation.framework in Frameworks */, + 586C3C40DC409C135B0AA19A /* CoreGraphics.framework in Frameworks */, + 93326C0FF4EE9F4BC32A072C /* UIKit.framework in Frameworks */, + 0B225B8CEA118D7190C02F8A /* AVFoundation.framework in Frameworks */, + D9993D35B97D8FF8F5F99A76 /* CoreData.framework in Frameworks */, + AB2D25C2602C7E82EA483032 /* CoreLocation.framework in Frameworks */, + D256FE4FDF4FDC2AF346BD7B /* CoreText.framework in Frameworks */, + 495DCD4434C57715950F77B4 /* GLKit.framework in Frameworks */, + 9CD7E5647D53C860A29AEF86 /* ImageIO.framework in Frameworks */, + A223A4F133AD8F8474895B2D /* Security.framework in Frameworks */, + BB82297CC4CD1B229302A5EB /* CoreBluetooth.framework in Frameworks */, + 2F8454DDC3837DA90C5E9114 /* Accelerate.framework in Frameworks */, + 6FC1A0CD8C09A8A7A8C394AA /* libc++.dylib in Frameworks */, + 1BC4F897035B4D58120062D4 /* libicucore.dylib in Frameworks */, + 7677FF7FF78329D9A3205687 /* libz.dylib in Frameworks */, + 9A09C9C77E8CEC959473BBB4 /* OpenGLES.framework in Frameworks */, + B29088B5D465871C06402A9A /* QuartzCore.framework in Frameworks */, + 0C50E0E757CCCCAFCC64FBB4 /* SystemConfiguration.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 1CC686768E6E7BE8890097AC /* PlacesSamples */ = { + isa = PBXGroup; + children = ( + 48C5F2798147CFFA14B5B7DD /* SDKDemoPlacePickerViewController.h */, + B8B2C467E3382D3E31EA92E1 /* SDKDemoPlacePickerViewController.m */, + 14532E524E38739F32328ECE /* Samples+Places.h */, + EBDF69733C905396E3568053 /* Samples+Places.m */, + ); + path = PlacesSamples; + sourceTree = ""; + }; + 2DBE6964ECA9681577AD08E9 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 837C86EA9AC87A3A5EA16145 /* AVFoundation.framework */, + D6A64F2A232BF392091BFB79 /* Accelerate.framework */, + ADDE981D53FECD067A463663 /* CoreBluetooth.framework */, + 9820B8516BCB7CD9A6553720 /* CoreData.framework */, + D2DFE1BF52A3A8AFFF379322 /* CoreFoundation.framework */, + 0416087FE83DCD914CF69FA9 /* CoreGraphics.framework */, + A38AE667ACADB5627CF67973 /* CoreLocation.framework */, + D8C04CF121E2CAC61D549125 /* CoreText.framework */, + C9926C6844E111CB23EF2E80 /* Foundation.framework */, + 7B47995B2A94F831E8B7DD0F /* GLKit.framework */, + D2325AC9E493AAC86F87681E /* GoogleMaps.framework */, + B247AC68273A6B9F29ED6CDC /* ImageIO.framework */, + 7BBAEFAF2820EDE4EBA5D943 /* OpenGLES.framework */, + 4D35CE548040C1EF3B8BD581 /* QuartzCore.framework */, + 425802FD822D22CC110119BA /* Security.framework */, + 4152CBF14080E0C84DFD6613 /* SystemConfiguration.framework */, + 9285758C5E07413BA20C8840 /* UIKit.framework */, + 193951C11D1549E7701FFC40 /* libc++.dylib */, + 8F6ED0C99E84A5FE46148309 /* libicucore.dylib */, + 74F5EF3ED006A948BCC2BF82 /* libobjc.dylib */, + AAA8B2B19FA46102744D14EF /* libz.dylib */, + ); + name = Frameworks; + sourceTree = ""; + }; + 4B066C2469FD81496EBDEF55 /* Resources */ = { + isa = PBXGroup; + children = ( + 69EBDE721FDFDCCDBB9DCC7A /* Images */, + 5F82E697DB805D8F5C7C7129 /* Museum-Icons */, + 959C749EEFBCC25DCDCC1416 /* Launch.xib */, + 75E000124A1962A304CEAAB8 /* aeroplane.png */, + 799CC7F35C34DAA014613DDF /* aeroplane@2x.png */, + 4C29D1A0DA47D1691C6CE0A5 /* argentina-large.png */, + EBDAAD248E528C9D828A2878 /* argentina.png */, + 3401A5B1795F7B7056A7F491 /* arrow.png */, + 46FF553F45838251496245F9 /* arrow@2x.png */, + 54743FFF10003AA647D1654F /* australia-large.png */, + C4D94F429262C3A09166D73F /* australia-large@2x.png */, + EA55E63E3ECB92756B8A8854 /* australia.png */, + 5AA08AB86BAE0FBBB8B3705F /* boat.png */, + 88F50C2BAD0B000697EBECCE /* boat@2x.png */, + D619B3D989A533F358F1D077 /* botswana-large.png */, + 97284C2589969381B1F2BF65 /* botswana.png */, + 8EB73A280D8FE0A1D2C054C8 /* bulgaria-large.png */, + BAF511F09C737A22E0A76E59 /* bulgaria.png */, + 2E95ACF5DD497E15A0B746DF /* glow-marker.png */, + 85109740028667AB1646AC2D /* glow-marker@2x.png */, + 1A597E83DFFF77F1EBD76B64 /* museum-exhibits.json */, + 72FF2F70BA1B0073BE1F375F /* newark_nj_1922.jpg */, + 85288BF143D609A7145A7846 /* popup_santa.png */, + D81C6119C4C7DE07FB42F86D /* popup_santa@2x.png */, + FE7C2DA207359F759D081156 /* step1.png */, + DC53293C94A672B4C62AD559 /* step1@2x.png */, + D83F65E0A08406E055A906B0 /* step2.png */, + 4C3CBB9D63F29447E8C3C06F /* step2@2x.png */, + 6D2F332D6F2FB20FE11DFB6E /* step3.png */, + 14A1E50F98F1EA56590AA120 /* step3@2x.png */, + 98A5F219881F5A5612905ABC /* step4.png */, + 62CBE24F5F8C7DF19AE8452C /* step4@2x.png */, + 3C1A74AB0EFA8C78AF23E564 /* step5.png */, + 7385EE81D06D3C1BD826B7C5 /* step5@2x.png */, + 359EF8FC1D5600228CFFBF4D /* step6.png */, + D05C1274204C92F13ABD8599 /* step6@2x.png */, + 3628691A5936DDD1821A622B /* step7.png */, + C7AB12C7756274D40E649762 /* step7@2x.png */, + E8CF929DF33D172F36F845E3 /* step8.png */, + FCCC58E7443B387046306EEF /* step8@2x.png */, + 3F1ABBF9B2E96BC488485119 /* track.json */, + ); + path = Resources; + sourceTree = ""; + }; + 55584DEF78F797697AA2FD6D /* GoogleMaps.framework/Resources */ = { + isa = PBXGroup; + children = ( + 8F59372BD761533A2A6B470A /* GoogleMaps.bundle */, + ); + path = GoogleMaps.framework/Resources; + sourceTree = ""; + }; + 5F82E697DB805D8F5C7C7129 /* Museum-Icons */ = { + isa = PBXGroup; + children = ( + 58B0EFEC1C69A989B6E84744 /* h1.png */, + EF3CF28401B594ADE426E656 /* h1@2x.png */, + FE2B3D4C04A8916BC8027A72 /* spitfire.png */, + 550E6B03BFE321336D066223 /* spitfire@2x.png */, + 7EC4132AB51E1500FF16E4C5 /* voyager.png */, + AB330C8620876E40BEC85968 /* voyager@2x.png */, + 487E4999CFF757EA18C569D8 /* x29.png */, + 124B199908A64B1EE958F3CA /* x29@2x.png */, + ); + path = "Museum-Icons"; + sourceTree = ""; + }; + 69EBDE721FDFDCCDBB9DCC7A /* Images */ = { + isa = PBXGroup; + children = ( + 77EA8532CD15A6B5E800415E /* Default-568h@2x.png */, + FA940308742FE4A8E2ACB6DB /* Default-Landscape@2x~ipad.png */, + 4F353004786E58271D76683E /* Default-Landscape~ipad.png */, + D03EB3995F5EF92504D8E44F /* Default-Portrait@2x~ipad.png */, + A56AF9AA60B75EF16CE3EF8C /* Default-Portrait~ipad.png */, + 842A2FB43838968D313B1783 /* Default.png */, + 0372FAEB924D0ADD012FBDFE /* Default@2x.png */, + 31DE8BA62A492FBC67E923AD /* sdkdemos_icon-72.png */, + 0F33C1C90D61AD0E2B502215 /* sdkdemos_icon-72@2x.png */, + CD99D73AD66B03243C670572 /* sdkdemos_icon.png */, + FD181A33530788C065AA2D90 /* sdkdemos_icon@2x.png */, + ); + path = Images; + sourceTree = ""; + }; + 6B58453C62AFCD886F0EED66 /* Source */ = { + isa = PBXGroup; + children = ( + 55584DEF78F797697AA2FD6D /* GoogleMaps.framework/Resources */, + 99979DB0F5D442647B9411F8 /* SDKDemos */, + ); + name = Source; + sourceTree = ""; + }; + 7F4C35C83CCF9EE02F5CB56A /* Samples */ = { + isa = PBXGroup; + children = ( + 63B21B38E81405568CD36449 /* AnimatedCurrentLocationViewController.h */, + 933F14F944559A5D5538023D /* AnimatedCurrentLocationViewController.m */, + 460EBDFBDFFE13DB517214A5 /* BasicMapViewController.h */, + 4BA4E139EA9FAA0D6A639CE6 /* BasicMapViewController.m */, + 59940AD9F86687DEA94EDE8C /* CameraViewController.h */, + 9A2729CB24AF1A2D245CD886 /* CameraViewController.m */, + 735DFE797020C7F09B21F773 /* CustomIndoorViewController.h */, + EB1CD2C01411A35969C872BA /* CustomIndoorViewController.m */, + ADB6F5B2F34C4461E2AFF686 /* CustomMarkersViewController.h */, + BD36A58B321268BB8E267874 /* CustomMarkersViewController.m */, + 81B8039817FFB9A398E1158B /* DoubleMapViewController.h */, + A578CA16809EBB3047B3C573 /* DoubleMapViewController.m */, + FD40AB7623BD1C9A81EA9239 /* FitBoundsViewController.h */, + 8B3EA327A271CA6A64D117A6 /* FitBoundsViewController.m */, + 989BBAF7DF1CD21CA2F9CC0E /* FixedPanoramaViewController.h */, + ABAA14F70E24A8E44326BBAE /* FixedPanoramaViewController.m */, + 1BA8114B0A4CDC672F1CBD6F /* GeocoderViewController.h */, + 3BD92F5F6AB10EDD9098A9DC /* GeocoderViewController.m */, + 3449C03C22DABB720D80FF72 /* GestureControlViewController.h */, + 0BA108F4D0C3BDA34CE54180 /* GestureControlViewController.m */, + 79A9E14215E011A6DFD2B0BA /* GradientPolylinesViewController.h */, + 7BFD80C8485C48F2C90C85A8 /* GradientPolylinesViewController.m */, + 778FAE1359A6570015F495EA /* GroundOverlayViewController.h */, + BD7A194DAB9B544294D7A2D0 /* GroundOverlayViewController.m */, + E4B1CC9979AFE466B59A9AC4 /* IndoorMuseumNavigationViewController.h */, + 3AAAD985B0FF3AF55E964A33 /* IndoorMuseumNavigationViewController.m */, + B6D2F25F8F4B1159C707B4A2 /* IndoorViewController.h */, + 0B6999063F311237F673B8B0 /* IndoorViewController.m */, + A849C0D00CED5DEF33AC6844 /* MapLayerViewController.h */, + 31F229C07CCFB0CFEBD70F68 /* MapLayerViewController.m */, + D1B2675ECA97CB1F5D0F5F88 /* MapTypesViewController.h */, + 5F3C1FEA265C2BC44CFFB4BD /* MapTypesViewController.m */, + 394AF35F597FB89E9D6A1E3D /* MapZoomViewController.h */, + 45580B3C558B48DD3359F2A1 /* MapZoomViewController.m */, + 7B4AF795B18672B900DE3568 /* MarkerEventsViewController.h */, + 1F1D873627D847B5C1B099FC /* MarkerEventsViewController.m */, + 13CBFFCFE30583D29D77B5A1 /* MarkerInfoWindowViewController.h */, + DC8661CA82A046ED2AF5B71F /* MarkerInfoWindowViewController.m */, + B1FA4EC4A89767E10B655CB0 /* MarkerLayerViewController.h */, + 9AB08565AAF1A341BC7D2A61 /* MarkerLayerViewController.m */, + 15F93E8BE938118367B428AA /* MarkersViewController.h */, + 9C2D5258F1365BCD57029138 /* MarkersViewController.m */, + AC4F4FF0F15305FE7DB327D5 /* MyLocationViewController.h */, + 6A37ED9FA16A22EFC586E32E /* MyLocationViewController.m */, + 2AB2A95CCD24024671158AD9 /* PanoramaViewController.h */, + DBBB2837C3A8ADB3D5191304 /* PanoramaViewController.m */, + BA7783E4FDFA7455B4EF6174 /* PolygonsViewController.h */, + 90258FFF395A5E25CCEC3AB0 /* PolygonsViewController.m */, + 6571C6FD38FB80E9657C6CF4 /* PolylinesViewController.h */, + 429F95111FD1F8B8A1C16865 /* PolylinesViewController.m */, + 778A178288F1E9593A03C6DB /* Samples.h */, + 043F8041B5649C26BCE75231 /* Samples.m */, + D7B0E6B7E378BF2301E42C6A /* StructuredGeocoderViewController.h */, + 64888C52E2E272FEFE7C18AA /* StructuredGeocoderViewController.m */, + 5977F6DB8B9BD6609BE664B0 /* TileLayerViewController.h */, + 6DEE18F2AE053B9A1DB19C5C /* TileLayerViewController.m */, + 09F0DD5C27A815E1A9720747 /* TrafficMapViewController.h */, + 78C6F7D665C6DD4328894967 /* TrafficMapViewController.m */, + E0D4EAD84FB1F606F6016E0B /* VisibleRegionViewController.h */, + DABC6731995E50EBF60E82DA /* VisibleRegionViewController.m */, + ); + path = Samples; + sourceTree = ""; + }; + 99979DB0F5D442647B9411F8 /* SDKDemos */ = { + isa = PBXGroup; + children = ( + 1CC686768E6E7BE8890097AC /* PlacesSamples */, + 4B066C2469FD81496EBDEF55 /* Resources */, + 7F4C35C83CCF9EE02F5CB56A /* Samples */, + C07CD02A92489C92FC822C3A /* SDKDemoAPIKey.h */, + A48DE20E9EF0EFE5F9656B51 /* SDKDemoAppDelegate.h */, + 5EC5186C29703467E4C2ED80 /* SDKDemoAppDelegate.m */, + 74A9950FBE5A377D1EBB2230 /* SDKDemoMasterViewController.h */, + 031103FAE4E394EA78895993 /* SDKDemoMasterViewController.m */, + 006739C6096E6B69D83F4A03 /* main.m */, + ); + path = SDKDemos; + sourceTree = ""; + }; + A2C8628B55F950FE20E7137C = { + isa = PBXGroup; + children = ( + 6B58453C62AFCD886F0EED66 /* Source */, + 2DBE6964ECA9681577AD08E9 /* Frameworks */, + E432E4A5C2DA557A55565E67 /* Products */, + D7938F561BAB3DB37E038EF7 /* Build */, + ); + sourceTree = ""; + }; + D7938F561BAB3DB37E038EF7 /* Build */ = { + isa = PBXGroup; + children = ( + FAF66F7D7BC732C1A5A896B0 /* SDKDemos.gyp */, + ); + name = Build; + sourceTree = ""; + }; + E432E4A5C2DA557A55565E67 /* Products */ = { + isa = PBXGroup; + children = ( + 656D0083D388D030EA0C9E3E /* SDKDemos.app */, + ); + name = Products; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + F0A34C824BF91068571FB9C9 /* SDKDemos */ = { + isa = PBXNativeTarget; + buildConfigurationList = 258F0E920477D8ADA8B68139 /* Build configuration list for PBXNativeTarget "SDKDemos" */; + buildPhases = ( + ADA7B6829517252313848C86 /* Resources */, + 2F23BF35CD9D8A7EBB7A3277 /* Sources */, + 9F427D7DE56744A968901ED9 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = SDKDemos; + productName = SDKDemos; + productReference = 656D0083D388D030EA0C9E3E /* SDKDemos.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + C0152C353C1C1C999BE34696 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = YES; + }; + buildConfigurationList = 3203C92569C9F50F18471A03 /* Build configuration list for PBXProject "SDKDemos" */; + compatibilityVersion = "Xcode 3.2"; + hasScannedForEncodings = 1; + mainGroup = A2C8628B55F950FE20E7137C; + projectDirPath = ""; + projectRoot = ""; + targets = ( + F0A34C824BF91068571FB9C9 /* SDKDemos */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + ADA7B6829517252313848C86 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + F17C0B74A739BF14D241F16B /* aeroplane.png in Resources */, + C230F93CE1D3114716A8BB21 /* aeroplane@2x.png in Resources */, + 800859CC04D2A160A19CBEF7 /* argentina-large.png in Resources */, + 526533CE6B1C0ED1B688F483 /* argentina.png in Resources */, + 1E50BD7CDD9844B9D59D100E /* arrow.png in Resources */, + 59FCB7DFF4C3A3F9D7D09CEF /* arrow@2x.png in Resources */, + 9931F73B835246208F13740C /* australia-large.png in Resources */, + 67D720CC13969DD22BFA987A /* australia-large@2x.png in Resources */, + 8E8CDF0B6C238C4A12355BA6 /* australia.png in Resources */, + 07143A1B00A26FB01E24A850 /* boat.png in Resources */, + 1C19BC7BF5541FECFAC6D1E7 /* boat@2x.png in Resources */, + 742CEB5206972B2A9DF79010 /* botswana-large.png in Resources */, + 0248CC2CFECAE929CBA46D32 /* botswana.png in Resources */, + 7D0AC180E00091E865619B3A /* bulgaria-large.png in Resources */, + FF90C83B482F1E9B6B3CEDE9 /* bulgaria.png in Resources */, + 15B014D5EE4D4B8A9E5F1FAD /* glow-marker.png in Resources */, + 41A1EB571CD2C902160F70BA /* glow-marker@2x.png in Resources */, + ABB9D9368C8C9AA0F4E98A5B /* Default-568h@2x.png in Resources */, + 3008E4FF586C0C4CCE5414A0 /* Default-Landscape@2x~ipad.png in Resources */, + 8D032C0D459BAA28785D4D82 /* Default-Landscape~ipad.png in Resources */, + FF5B48D04F4CA6E5E78737D6 /* Default-Portrait@2x~ipad.png in Resources */, + 158A3EEE3E90A6CDE07C8D3E /* Default-Portrait~ipad.png in Resources */, + 0804F89A761192E17C4E14A0 /* Default.png in Resources */, + 4A32F95C94EB31838B53D74D /* Default@2x.png in Resources */, + D86BD487B00D457841F89438 /* sdkdemos_icon-72.png in Resources */, + 14AEFDCDCBCBA9BD4D739777 /* sdkdemos_icon-72@2x.png in Resources */, + B45757B5CE9CEDE5C085AC17 /* sdkdemos_icon.png in Resources */, + EDBD021F4894885DCBCF392F /* sdkdemos_icon@2x.png in Resources */, + DD3DCD76A940EBD4E58E76F3 /* h1.png in Resources */, + 8711D42833BA78FA57565605 /* h1@2x.png in Resources */, + 37D656EEA738FCF3B8FAAE89 /* spitfire.png in Resources */, + EB83CCF71D1F521D867360E6 /* spitfire@2x.png in Resources */, + ED6DEEBDC0298BF1AC19F0B0 /* voyager.png in Resources */, + B65254ACFCCA101144AEA425 /* voyager@2x.png in Resources */, + C6C66578EE0A3295A2392185 /* x29.png in Resources */, + E5CEE60985676D8CC6AC0FE8 /* x29@2x.png in Resources */, + C9B58772C3374D132D54B79E /* popup_santa.png in Resources */, + D8114F384AA6E0242578FAC3 /* popup_santa@2x.png in Resources */, + B3D44230385773BFD2CB22E7 /* step1.png in Resources */, + 150069CF910745504A7E3F7F /* step1@2x.png in Resources */, + 439219410CB49A6BB29EA6AA /* step2.png in Resources */, + EBDEB695207B4D4D9F3C677F /* step2@2x.png in Resources */, + DAD13235132F0A7B9A7D9A86 /* step3.png in Resources */, + 740C876D089202BF76EFF6D7 /* step3@2x.png in Resources */, + 0966341B5DECEEB70F824FB4 /* step4.png in Resources */, + 6E44FC6890A0979EED438270 /* step4@2x.png in Resources */, + 0A9073D3525470D2441215B2 /* step5.png in Resources */, + F844A584365DC27FDFC38368 /* step5@2x.png in Resources */, + 7E32939A0E72D31989291E78 /* step6.png in Resources */, + FAA88DA5B6CB123CB79FAB1E /* step6@2x.png in Resources */, + D5B79AD1DE6AFB7CA050796F /* step7.png in Resources */, + 696DC26814A711ED1FB8ACC8 /* step7@2x.png in Resources */, + 7BDA92EDDAB1F6D3BD5E3D33 /* step8.png in Resources */, + A1C1CC6329A61E8AC8DEF45E /* step8@2x.png in Resources */, + 099C7BEF376638CC84DE5779 /* newark_nj_1922.jpg in Resources */, + 81EE689DC035CAF1D9C479FD /* museum-exhibits.json in Resources */, + 93179278EF404CB0AB3AD109 /* track.json in Resources */, + F8DEB16CA5084A02112ACF8E /* Launch.xib in Resources */, + 6C86DB77A73CAEE2C48E6668 /* GoogleMaps.bundle in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 2F23BF35CD9D8A7EBB7A3277 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 13F27F941CFF1FF90A26E9FB /* main.m in Sources */, + 984203D4FC972F6775785F60 /* Samples+Places.m in Sources */, + 59B1403950BAF2A027E7AD06 /* SDKDemoPlacePickerViewController.m in Sources */, + 8305DE85D47096FF5E6B2C7F /* AnimatedCurrentLocationViewController.m in Sources */, + 1E848AC8B09FCD0B029B2515 /* BasicMapViewController.m in Sources */, + 4DAF1D27C71D97CEC4D35A40 /* CameraViewController.m in Sources */, + B5C57041E4F43FACD9D7855D /* CustomIndoorViewController.m in Sources */, + 3E0BB6C829DA62BCB801089E /* CustomMarkersViewController.m in Sources */, + C38470C15BFF9DAA51DB24CE /* DoubleMapViewController.m in Sources */, + 077F9A9BF20CCC7396BA038D /* FitBoundsViewController.m in Sources */, + F776F3C2E208EE9378C970C9 /* FixedPanoramaViewController.m in Sources */, + EB1E651BF9DC2712EDB689E2 /* GeocoderViewController.m in Sources */, + 5AFC6A9EF7E5334274F2003B /* GestureControlViewController.m in Sources */, + 73B795E621B99087515948DB /* GradientPolylinesViewController.m in Sources */, + BFAF2B58B5447DC7F6700608 /* GroundOverlayViewController.m in Sources */, + 5E25A0B2F58A1DC71D3D095E /* IndoorMuseumNavigationViewController.m in Sources */, + D81F4D7B477B99779B2E26BB /* IndoorViewController.m in Sources */, + D9E9F4337CCE7C06D731C309 /* MapLayerViewController.m in Sources */, + B62B3CD1C9493C6DC10D0F6A /* MapTypesViewController.m in Sources */, + 2351AA58A2D1B916CE6FC02F /* MapZoomViewController.m in Sources */, + 22E010704EB4D09C613E3D02 /* MarkerEventsViewController.m in Sources */, + 7CA30F964585636F7722EF50 /* MarkerInfoWindowViewController.m in Sources */, + 0AB2EA98279BC321EA4EFC30 /* MarkerLayerViewController.m in Sources */, + FB3CCF78441EF08378478AAA /* MarkersViewController.m in Sources */, + 35F868C56688C0541E7C08D6 /* MyLocationViewController.m in Sources */, + 96A9D65C45A6AC6A72B7A83D /* PanoramaViewController.m in Sources */, + 58ADE659AEBDB89F90AA0006 /* PolygonsViewController.m in Sources */, + E471D0D1812EBBED5E1BFC3E /* PolylinesViewController.m in Sources */, + C8FAEF11B1140F995C4AF50E /* Samples.m in Sources */, + A211BD2291B236DFBDB6F703 /* StructuredGeocoderViewController.m in Sources */, + BCDA5CF64C63BF71C5805642 /* TileLayerViewController.m in Sources */, + 317AF024CEE06AB3E759BE77 /* TrafficMapViewController.m in Sources */, + 55C349437FEF9D735F70C826 /* VisibleRegionViewController.m in Sources */, + 2B53A795F430861957A94EB2 /* SDKDemoAppDelegate.m in Sources */, + F67ADB09D12D294ABF56944E /* SDKDemoMasterViewController.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 182F5544C35981299E88F8A3 /* Default */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_OBJC_ARC = YES; + FRAMEWORK_SEARCH_PATHS = "$(SRCROOT)"; + INFOPLIST_FILE = "./SDKDemos/SDKDemo-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 6.0; + LIBRARY_SEARCH_PATHS = ( + ., + "$(SDKROOT)/System/Library/Frameworks", + ); + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_NAME = SDKDemos; + TARGETED_DEVICE_FAMILY = "1,2"; + USER_HEADER_SEARCH_PATHS = "$(SRCROOT)"; + USE_HEADERMAP = NO; + VALID_ARCHS = "i386 armv7"; + WRAPPER_PREFIX = ""; + }; + name = Default; + }; + A37B5359681FA0FDEE47E9A5 /* Default */ = { + isa = XCBuildConfiguration; + buildSettings = { + INTERMEDIATE_DIR = "$(PROJECT_DERIVED_FILE_DIR)/$(CONFIGURATION)"; + SDKROOT = iphoneos; + SHARED_INTERMEDIATE_DIR = "$(SYMROOT)/DerivedSources/$(CONFIGURATION)"; + }; + name = Default; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 258F0E920477D8ADA8B68139 /* Build configuration list for PBXNativeTarget "SDKDemos" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 182F5544C35981299E88F8A3 /* Default */, + ); + defaultConfigurationIsVisible = 1; + defaultConfigurationName = Default; + }; + 3203C92569C9F50F18471A03 /* Build configuration list for PBXProject "SDKDemos" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + A37B5359681FA0FDEE47E9A5 /* Default */, + ); + defaultConfigurationIsVisible = 1; + defaultConfigurationName = Default; + }; +/* End XCConfigurationList section */ + }; + rootObject = C0152C353C1C1C999BE34696 /* Project object */; +} diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/PlacesSamples/SDKDemoPlacePickerViewController.h b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/PlacesSamples/SDKDemoPlacePickerViewController.h new file mode 100644 index 0000000..4f6afc2 --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/PlacesSamples/SDKDemoPlacePickerViewController.h @@ -0,0 +1,5 @@ +#import + +@interface SDKDemoPlacePickerViewController : UIViewController + +@end diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/PlacesSamples/SDKDemoPlacePickerViewController.m b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/PlacesSamples/SDKDemoPlacePickerViewController.m new file mode 100644 index 0000000..5a8823a --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/PlacesSamples/SDKDemoPlacePickerViewController.m @@ -0,0 +1,62 @@ +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +#import "SDKDemos/PlacesSamples/SDKDemoPlacePickerViewController.h" + +#import "SDKDemos/SDKDemoAPIKey.h" + + +@implementation SDKDemoPlacePickerViewController { + GMSPlacePicker *_placePicker; +} + +- (instancetype)init { + if ((self = [super init])) { + CLLocationCoordinate2D southWestSydney = CLLocationCoordinate2DMake(-33.8659, 151.1953); + CLLocationCoordinate2D northEastSydney = CLLocationCoordinate2DMake(-33.8645, 151.1969); + GMSCoordinateBounds *sydneyBounds = + [[GMSCoordinateBounds alloc] initWithCoordinate:southWestSydney coordinate:northEastSydney]; + GMSPlacePickerConfig *config = + [[GMSPlacePickerConfig alloc] initWithViewport:sydneyBounds]; + _placePicker = [[GMSPlacePicker alloc] initWithConfig:config]; + } + return self; +} + +- (void)viewDidLoad { + [super viewDidLoad]; + UITextView *textView = [[UITextView alloc] initWithFrame:self.view.bounds]; + textView.delegate = self; + textView.editable = NO; + [self.view addSubview:textView]; + __weak UITextView *weakResultView = textView; + [_placePicker pickPlaceWithCallback:^(GMSPlace *place, NSError *error) { + UITextView *resultView = weakResultView; + if (resultView == nil) { + return; + } + if (place) { + NSMutableAttributedString *text = + [[NSMutableAttributedString alloc] initWithString:[place description]]; + [text appendAttributedString:[[NSAttributedString alloc] initWithString:@"\n\n"]]; + [text appendAttributedString:place.attributions]; + resultView.attributedText = text; + } else if (error) { + resultView.text = + [NSString stringWithFormat:@"Place picking failed with error: %@", error]; + } else { + resultView.text = @"Place picking cancelled."; + } + }]; +} + +#pragma mark - UITextViewDelegate + +- (BOOL)textView:(UITextView *)textView + shouldInteractWithURL:(NSURL *)url + inRange:(NSRange)characterRange { + // Make links clickable. + return YES; +} +@end diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/PlacesSamples/Samples+Places.h b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/PlacesSamples/Samples+Places.h new file mode 100644 index 0000000..376a8ec --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/PlacesSamples/Samples+Places.h @@ -0,0 +1,7 @@ +#import "SDKDemos/Samples/Samples.h" + +@interface Samples (Places) + ++ (NSArray *)placesDemos; + +@end diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/PlacesSamples/Samples+Places.m b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/PlacesSamples/Samples+Places.m new file mode 100644 index 0000000..6f4d194 --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/PlacesSamples/Samples+Places.m @@ -0,0 +1,19 @@ +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +#import "SDKDemos/PlacesSamples/Samples+Places.h" + +#import "SDKDemos/PlacesSamples/SDKDemoPlacePickerViewController.h" + +@implementation Samples (Places) + ++ (NSArray *)placesDemos { + return @[ + [Samples newDemo:[SDKDemoPlacePickerViewController class] + withTitle:@"Places API Place Picker" + andDescription:nil], + ]; +} + +@end diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/Images/Default-568h@2x.png b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/Images/Default-568h@2x.png new file mode 100644 index 0000000..8443cbe Binary files /dev/null and b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/Images/Default-568h@2x.png differ diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/Images/Default-Landscape@2x~ipad.png b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/Images/Default-Landscape@2x~ipad.png new file mode 100644 index 0000000..3efbab7 Binary files /dev/null and b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/Images/Default-Landscape@2x~ipad.png differ diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/Images/Default-Landscape~ipad.png b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/Images/Default-Landscape~ipad.png new file mode 100644 index 0000000..4cfca97 Binary files /dev/null and b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/Images/Default-Landscape~ipad.png differ diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/Images/Default-Portrait@2x~ipad.png b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/Images/Default-Portrait@2x~ipad.png new file mode 100644 index 0000000..66789fb Binary files /dev/null and b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/Images/Default-Portrait@2x~ipad.png differ diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/Images/Default-Portrait~ipad.png b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/Images/Default-Portrait~ipad.png new file mode 100644 index 0000000..0a62073 Binary files /dev/null and b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/Images/Default-Portrait~ipad.png differ diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/Images/Default.png b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/Images/Default.png new file mode 100644 index 0000000..bcbeb8c Binary files /dev/null and b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/Images/Default.png differ diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/Images/Default@2x.png b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/Images/Default@2x.png new file mode 100644 index 0000000..a631978 Binary files /dev/null and b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/Images/Default@2x.png differ diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/Images/sdkdemos_icon-72.png b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/Images/sdkdemos_icon-72.png new file mode 100644 index 0000000..689b3a2 Binary files /dev/null and b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/Images/sdkdemos_icon-72.png differ diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/Images/sdkdemos_icon-72@2x.png b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/Images/sdkdemos_icon-72@2x.png new file mode 100644 index 0000000..3abcd45 Binary files /dev/null and b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/Images/sdkdemos_icon-72@2x.png differ diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/Images/sdkdemos_icon.png b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/Images/sdkdemos_icon.png new file mode 100644 index 0000000..6e98095 Binary files /dev/null and b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/Images/sdkdemos_icon.png differ diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/Images/sdkdemos_icon@2x.png b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/Images/sdkdemos_icon@2x.png new file mode 100644 index 0000000..0979478 Binary files /dev/null and b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/Images/sdkdemos_icon@2x.png differ diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/Launch.xib b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/Launch.xib new file mode 100644 index 0000000..c9334a5 --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/Launch.xib @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/Museum-Icons/h1.png b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/Museum-Icons/h1.png new file mode 100644 index 0000000..9859ded Binary files /dev/null and b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/Museum-Icons/h1.png differ diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/Museum-Icons/h1@2x.png b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/Museum-Icons/h1@2x.png new file mode 100644 index 0000000..0eb550f Binary files /dev/null and b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/Museum-Icons/h1@2x.png differ diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/Museum-Icons/spitfire.png b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/Museum-Icons/spitfire.png new file mode 100644 index 0000000..ed82a1a Binary files /dev/null and b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/Museum-Icons/spitfire.png differ diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/Museum-Icons/spitfire@2x.png b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/Museum-Icons/spitfire@2x.png new file mode 100644 index 0000000..883152c Binary files /dev/null and b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/Museum-Icons/spitfire@2x.png differ diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/Museum-Icons/voyager.png b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/Museum-Icons/voyager.png new file mode 100644 index 0000000..2f83887 Binary files /dev/null and b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/Museum-Icons/voyager.png differ diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/Museum-Icons/voyager@2x.png b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/Museum-Icons/voyager@2x.png new file mode 100644 index 0000000..f796311 Binary files /dev/null and b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/Museum-Icons/voyager@2x.png differ diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/Museum-Icons/x29.png b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/Museum-Icons/x29.png new file mode 100644 index 0000000..5c84651 Binary files /dev/null and b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/Museum-Icons/x29.png differ diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/Museum-Icons/x29@2x.png b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/Museum-Icons/x29@2x.png new file mode 100644 index 0000000..7fb4758 Binary files /dev/null and b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/Museum-Icons/x29@2x.png differ diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/aeroplane.png b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/aeroplane.png new file mode 100644 index 0000000..0ca6d73 Binary files /dev/null and b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/aeroplane.png differ diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/aeroplane@2x.png b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/aeroplane@2x.png new file mode 100644 index 0000000..013d570 Binary files /dev/null and b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/aeroplane@2x.png differ diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/ar.lproj/InfoPlist.strings b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/ar.lproj/InfoPlist.strings new file mode 100644 index 0000000..477b28f --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/ar.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/argentina-large.png b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/argentina-large.png new file mode 100644 index 0000000..50ee6b2 Binary files /dev/null and b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/argentina-large.png differ diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/argentina.png b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/argentina.png new file mode 100644 index 0000000..23637d1 Binary files /dev/null and b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/argentina.png differ diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/arrow.png b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/arrow.png new file mode 100644 index 0000000..43a0465 Binary files /dev/null and b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/arrow.png differ diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/arrow@2x.png b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/arrow@2x.png new file mode 100644 index 0000000..318efd5 Binary files /dev/null and b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/arrow@2x.png differ diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/australia-large.png b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/australia-large.png new file mode 100644 index 0000000..098821d Binary files /dev/null and b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/australia-large.png differ diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/australia-large@2x.png b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/australia-large@2x.png new file mode 100644 index 0000000..8d28a75 Binary files /dev/null and b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/australia-large@2x.png differ diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/australia.png b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/australia.png new file mode 100644 index 0000000..b2e7c40 Binary files /dev/null and b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/australia.png differ diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/boat.png b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/boat.png new file mode 100644 index 0000000..0c6c08b Binary files /dev/null and b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/boat.png differ diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/boat@2x.png b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/boat@2x.png new file mode 100644 index 0000000..609863f Binary files /dev/null and b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/boat@2x.png differ diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/botswana-large.png b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/botswana-large.png new file mode 100644 index 0000000..ee171c8 Binary files /dev/null and b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/botswana-large.png differ diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/botswana.png b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/botswana.png new file mode 100644 index 0000000..1e34013 Binary files /dev/null and b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/botswana.png differ diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/bulgaria-large.png b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/bulgaria-large.png new file mode 100644 index 0000000..ab22b29 Binary files /dev/null and b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/bulgaria-large.png differ diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/bulgaria.png b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/bulgaria.png new file mode 100644 index 0000000..bffb2af Binary files /dev/null and b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/bulgaria.png differ diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/ca.lproj/InfoPlist.strings b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/ca.lproj/InfoPlist.strings new file mode 100644 index 0000000..477b28f --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/ca.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/cs.lproj/InfoPlist.strings b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/cs.lproj/InfoPlist.strings new file mode 100644 index 0000000..477b28f --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/cs.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/da.lproj/InfoPlist.strings b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/da.lproj/InfoPlist.strings new file mode 100644 index 0000000..477b28f --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/da.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/de.lproj/InfoPlist.strings b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/de.lproj/InfoPlist.strings new file mode 100644 index 0000000..477b28f --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/de.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/el.lproj/InfoPlist.strings b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/el.lproj/InfoPlist.strings new file mode 100644 index 0000000..477b28f --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/el.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/en.lproj/InfoPlist.strings b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/en.lproj/InfoPlist.strings new file mode 100644 index 0000000..477b28f --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/en.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/en_GB.lproj/InfoPlist.strings b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/en_GB.lproj/InfoPlist.strings new file mode 100644 index 0000000..477b28f --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/en_GB.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/es.lproj/InfoPlist.strings b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/es.lproj/InfoPlist.strings new file mode 100644 index 0000000..477b28f --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/es.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/fi.lproj/InfoPlist.strings b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/fi.lproj/InfoPlist.strings new file mode 100644 index 0000000..477b28f --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/fi.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/fr.lproj/InfoPlist.strings b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/fr.lproj/InfoPlist.strings new file mode 100644 index 0000000..477b28f --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/fr.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/glow-marker.png b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/glow-marker.png new file mode 100644 index 0000000..1a4b884 Binary files /dev/null and b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/glow-marker.png differ diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/glow-marker@2x.png b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/glow-marker@2x.png new file mode 100644 index 0000000..f061e16 Binary files /dev/null and b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/glow-marker@2x.png differ diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/he.lproj/InfoPlist.strings b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/he.lproj/InfoPlist.strings new file mode 100644 index 0000000..477b28f --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/he.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/hr.lproj/InfoPlist.strings b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/hr.lproj/InfoPlist.strings new file mode 100644 index 0000000..477b28f --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/hr.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/hu.lproj/InfoPlist.strings b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/hu.lproj/InfoPlist.strings new file mode 100644 index 0000000..477b28f --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/hu.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/id.lproj/InfoPlist.strings b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/id.lproj/InfoPlist.strings new file mode 100644 index 0000000..477b28f --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/id.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/it.lproj/InfoPlist.strings b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/it.lproj/InfoPlist.strings new file mode 100644 index 0000000..477b28f --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/it.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/ja.lproj/InfoPlist.strings b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/ja.lproj/InfoPlist.strings new file mode 100644 index 0000000..477b28f --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/ja.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/ko.lproj/InfoPlist.strings b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/ko.lproj/InfoPlist.strings new file mode 100644 index 0000000..477b28f --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/ko.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/ms.lproj/InfoPlist.strings b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/ms.lproj/InfoPlist.strings new file mode 100644 index 0000000..477b28f --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/ms.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/museum-exhibits.json b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/museum-exhibits.json new file mode 100644 index 0000000..231334b --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/museum-exhibits.json @@ -0,0 +1,30 @@ +[ + { + "key": "h1", + "name": "Hughes H-1", + "lat": 38.8879, + "lng": -77.02085, + "level": "1", + }, + { + "key": "voyager", + "name": "Rutan Voyager", + "lat": 38.8880, + "lng": -77.0199, + "level": "1", + }, + { + "key": "spitfire", + "name": "Supermarine Spitfire", + "lat": 38.8879, + "lng": -77.0208, + "level": "2", + }, + { + "key": "x29", + "name": "Grumman X-29", + "lat": 38.88845, + "lng": -77.01875, + "level": "2", + } +] \ No newline at end of file diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/nb.lproj/InfoPlist.strings b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/nb.lproj/InfoPlist.strings new file mode 100644 index 0000000..477b28f --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/nb.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/newark_nj_1922.jpg b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/newark_nj_1922.jpg new file mode 100644 index 0000000..1f4ae59 Binary files /dev/null and b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/newark_nj_1922.jpg differ diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/nl.lproj/InfoPlist.strings b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/nl.lproj/InfoPlist.strings new file mode 100644 index 0000000..477b28f --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/nl.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/pl.lproj/InfoPlist.strings b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/pl.lproj/InfoPlist.strings new file mode 100644 index 0000000..477b28f --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/pl.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/popup_santa.png b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/popup_santa.png new file mode 100644 index 0000000..50b8f59 Binary files /dev/null and b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/popup_santa.png differ diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/popup_santa@2x.png b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/popup_santa@2x.png new file mode 100644 index 0000000..4bdd7a3 Binary files /dev/null and b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/popup_santa@2x.png differ diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/pt.lproj/InfoPlist.strings b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/pt.lproj/InfoPlist.strings new file mode 100644 index 0000000..477b28f --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/pt.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/pt_PT.lproj/InfoPlist.strings b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/pt_PT.lproj/InfoPlist.strings new file mode 100644 index 0000000..477b28f --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/pt_PT.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/ro.lproj/InfoPlist.strings b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/ro.lproj/InfoPlist.strings new file mode 100644 index 0000000..477b28f --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/ro.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/ru.lproj/InfoPlist.strings b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/ru.lproj/InfoPlist.strings new file mode 100644 index 0000000..477b28f --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/ru.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/sk.lproj/InfoPlist.strings b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/sk.lproj/InfoPlist.strings new file mode 100644 index 0000000..477b28f --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/sk.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/step1.png b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/step1.png new file mode 100644 index 0000000..172e9fd Binary files /dev/null and b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/step1.png differ diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/step1@2x.png b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/step1@2x.png new file mode 100644 index 0000000..aceedc6 Binary files /dev/null and b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/step1@2x.png differ diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/step2.png b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/step2.png new file mode 100644 index 0000000..c1c762e Binary files /dev/null and b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/step2.png differ diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/step2@2x.png b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/step2@2x.png new file mode 100644 index 0000000..1457248 Binary files /dev/null and b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/step2@2x.png differ diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/step3.png b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/step3.png new file mode 100644 index 0000000..2dcc088 Binary files /dev/null and b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/step3.png differ diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/step3@2x.png b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/step3@2x.png new file mode 100644 index 0000000..7e0544c Binary files /dev/null and b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/step3@2x.png differ diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/step4.png b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/step4.png new file mode 100644 index 0000000..a1e8155 Binary files /dev/null and b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/step4.png differ diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/step4@2x.png b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/step4@2x.png new file mode 100644 index 0000000..6bcc25b Binary files /dev/null and b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/step4@2x.png differ diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/step5.png b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/step5.png new file mode 100644 index 0000000..4ff116e Binary files /dev/null and b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/step5.png differ diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/step5@2x.png b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/step5@2x.png new file mode 100644 index 0000000..ec16e0d Binary files /dev/null and b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/step5@2x.png differ diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/step6.png b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/step6.png new file mode 100644 index 0000000..09d9b37 Binary files /dev/null and b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/step6.png differ diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/step6@2x.png b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/step6@2x.png new file mode 100644 index 0000000..e759f9d Binary files /dev/null and b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/step6@2x.png differ diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/step7.png b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/step7.png new file mode 100644 index 0000000..60fbf74 Binary files /dev/null and b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/step7.png differ diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/step7@2x.png b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/step7@2x.png new file mode 100644 index 0000000..2719641 Binary files /dev/null and b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/step7@2x.png differ diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/step8.png b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/step8.png new file mode 100644 index 0000000..f51cccc Binary files /dev/null and b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/step8.png differ diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/step8@2x.png b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/step8@2x.png new file mode 100644 index 0000000..81a6196 Binary files /dev/null and b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/step8@2x.png differ diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/sv.lproj/InfoPlist.strings b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/sv.lproj/InfoPlist.strings new file mode 100644 index 0000000..477b28f --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/sv.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/th.lproj/InfoPlist.strings b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/th.lproj/InfoPlist.strings new file mode 100644 index 0000000..477b28f --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/th.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/tr.lproj/InfoPlist.strings b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/tr.lproj/InfoPlist.strings new file mode 100644 index 0000000..477b28f --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/tr.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/track.json b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/track.json new file mode 100644 index 0000000..1d49290 --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/track.json @@ -0,0 +1 @@ +[{"lat": "44.145331", "lng": "9.661942", "elevation": "173.8000030517578", "time": "2013-09-20T08:40:00.855Z"}, {"lat": "44.145157", "lng": "9.661917", "elevation": "177.3000030517578", "time": "2013-09-20T08:40:01.824Z"}, {"lat": "44.14505", "lng": "9.662049", "elevation": "170.60000610351563", "time": "2013-09-20T08:40:02.945Z"}, {"lat": "44.145", "lng": "9.662165", "elevation": "156.5", "time": "2013-09-20T08:40:03.828Z"}, {"lat": "44.144918", "lng": "9.662227", "elevation": "130.6999969482422", "time": "2013-09-20T08:40:04.823Z"}, {"lat": "44.144945", "lng": "9.662122", "elevation": "149.5", "time": "2013-09-20T08:40:06.123Z"}, {"lat": "44.14503", "lng": "9.662141", "elevation": "152.89999389648438", "time": "2013-09-20T08:40:07.122Z"}, {"lat": "44.144943", "lng": "9.662169", "elevation": "155.3000030517578", "time": "2013-09-20T08:40:19.117Z"}, {"lat": "44.144937", "lng": "9.66217", "elevation": "155.5", "time": "2013-09-20T08:40:20.157Z"}, {"lat": "44.144933", "lng": "9.662171", "elevation": "154.8000030517578", "time": "2013-09-20T08:40:22.132Z"}, {"lat": "44.144933", "lng": "9.662173", "elevation": "155.0", "time": "2013-09-20T08:40:23.141Z"}, {"lat": "44.144937", "lng": "9.662186", "elevation": "155.8000030517578", "time": "2013-09-20T08:40:45.224Z"}, {"lat": "44.144934", "lng": "9.66219", "elevation": "158.5", "time": "2013-09-20T08:40:46.191Z"}, {"lat": "44.144911", "lng": "9.662248", "elevation": "161.6999969482422", "time": "2013-09-20T08:40:59.133Z"}, {"lat": "44.144911", "lng": "9.662249", "elevation": "161.8000030517578", "time": "2013-09-20T08:41:00.124Z"}, {"lat": "44.14491", "lng": "9.662258", "elevation": "161.6999969482422", "time": "2013-09-20T08:41:09.127Z"}, {"lat": "44.144907", "lng": "9.662263", "elevation": "162.0", "time": "2013-09-20T08:41:10.185Z"}, {"lat": "44.144884", "lng": "9.662378", "elevation": "161.3000030517578", "time": "2013-09-20T08:41:17.137Z"}, {"lat": "44.144879", "lng": "9.662397", "elevation": "161.1999969482422", "time": "2013-09-20T08:41:18.211Z"}, {"lat": "44.144874", "lng": "9.662517", "elevation": "163.0", "time": "2013-09-20T08:41:26.217Z"}, {"lat": "44.144877", "lng": "9.66253", "elevation": "163.39999389648438", "time": "2013-09-20T08:41:27.220Z"}, {"lat": "44.144812", "lng": "9.662617", "elevation": "166.8000030517578", "time": "2013-09-20T08:41:36.137Z"}, {"lat": "44.144806", "lng": "9.662625", "elevation": "166.89999389648438", "time": "2013-09-20T08:41:37.146Z"}, {"lat": "44.14477", "lng": "9.662604", "elevation": "167.10000610351563", "time": "2013-09-20T08:41:49.143Z"}, {"lat": "44.14477", "lng": "9.662607", "elevation": "167.1999969482422", "time": "2013-09-20T08:41:50.138Z"}, {"lat": "44.144763", "lng": "9.662619", "elevation": "168.0", "time": "2013-09-20T08:41:58.146Z"}, {"lat": "44.14476", "lng": "9.662618", "elevation": "168.3000030517578", "time": "2013-09-20T08:41:59.133Z"}, {"lat": "44.144755", "lng": "9.662616", "elevation": "168.5", "time": "2013-09-20T08:42:01.147Z"}, {"lat": "44.144755", "lng": "9.662616", "elevation": "168.6999969482422", "time": "2013-09-20T08:42:02.133Z"}, {"lat": "44.144754", "lng": "9.662623", "elevation": "169.8000030517578", "time": "2013-09-20T08:43:18.202Z"}, {"lat": "44.144753", "lng": "9.662633", "elevation": "169.39999389648438", "time": "2013-09-20T08:43:19.274Z"}, {"lat": "44.144768", "lng": "9.662683", "elevation": "173.8000030517578", "time": "2013-09-20T08:43:28.140Z"}, {"lat": "44.144768", "lng": "9.662684", "elevation": "174.0", "time": "2013-09-20T08:43:29.177Z"}, {"lat": "44.144764", "lng": "9.662687", "elevation": "172.89999389648438", "time": "2013-09-20T08:43:33.140Z"}, {"lat": "44.144761", "lng": "9.662692", "elevation": "173.3000030517578", "time": "2013-09-20T08:43:34.147Z"}, {"lat": "44.144755", "lng": "9.662699", "elevation": "173.1999969482422", "time": "2013-09-20T08:43:37.220Z"}, {"lat": "44.144754", "lng": "9.6627", "elevation": "173.1999969482422", "time": "2013-09-20T08:43:38.164Z"}, {"lat": "44.144755", "lng": "9.662702", "elevation": "173.3000030517578", "time": "2013-09-20T08:43:43.148Z"}, {"lat": "44.144756", "lng": "9.662709", "elevation": "172.6999969482422", "time": "2013-09-20T08:43:44.141Z"}, {"lat": "44.144716", "lng": "9.662816", "elevation": "179.5", "time": "2013-09-20T08:43:51.157Z"}, {"lat": "44.144717", "lng": "9.662831", "elevation": "180.8000030517578", "time": "2013-09-20T08:43:52.141Z"}, {"lat": "44.1447", "lng": "9.662945", "elevation": "182.3000030517578", "time": "2013-09-20T08:44:01.165Z"}, {"lat": "44.144696", "lng": "9.662956", "elevation": "181.89999389648438", "time": "2013-09-20T08:44:02.153Z"}, {"lat": "44.144679", "lng": "9.662965", "elevation": "181.6999969482422", "time": "2013-09-20T08:44:08.135Z"}, {"lat": "44.144679", "lng": "9.662966", "elevation": "181.60000610351563", "time": "2013-09-20T08:44:09.139Z"}, {"lat": "44.14469", "lng": "9.66299", "elevation": "183.1999969482422", "time": "2013-09-20T08:44:26.146Z"}, {"lat": "44.144687", "lng": "9.662998", "elevation": "182.89999389648438", "time": "2013-09-20T08:44:27.145Z"}, {"lat": "44.144661", "lng": "9.663117", "elevation": "193.1999969482422", "time": "2013-09-20T08:44:38.177Z"}, {"lat": "44.144658", "lng": "9.66312", "elevation": "193.1999969482422", "time": "2013-09-20T08:44:39.232Z"}, {"lat": "44.144581", "lng": "9.663173", "elevation": "199.3000030517578", "time": "2013-09-20T08:44:51.156Z"}, {"lat": "44.144572", "lng": "9.66319", "elevation": "199.39999389648438", "time": "2013-09-20T08:44:52.153Z"}, {"lat": "44.144518", "lng": "9.663271", "elevation": "201.1999969482422", "time": "2013-09-20T08:44:57.156Z"}, {"lat": "44.144506", "lng": "9.663276", "elevation": "202.5", "time": "2013-09-20T08:44:58.141Z"}, {"lat": "44.144498", "lng": "9.663277", "elevation": "202.3000030517578", "time": "2013-09-20T08:45:02.212Z"}, {"lat": "44.144506", "lng": "9.663277", "elevation": "201.8000030517578", "time": "2013-09-20T08:45:03.249Z"}, {"lat": "44.144513", "lng": "9.66328", "elevation": "201.1999969482422", "time": "2013-09-20T08:45:04.186Z"}, {"lat": "44.144526", "lng": "9.663302", "elevation": "199.5", "time": "2013-09-20T08:45:09.163Z"}, {"lat": "44.144526", "lng": "9.663298", "elevation": "199.89999389648438", "time": "2013-09-20T08:45:10.157Z"}, {"lat": "44.144527", "lng": "9.663291", "elevation": "200.6999969482422", "time": "2013-09-20T08:45:11.229Z"}, {"lat": "44.144527", "lng": "9.663281", "elevation": "201.8000030517578", "time": "2013-09-20T08:45:12.229Z"}, {"lat": "44.144522", "lng": "9.663257", "elevation": "202.0", "time": "2013-09-20T08:45:17.165Z"}, {"lat": "44.14452", "lng": "9.663259", "elevation": "201.60000610351563", "time": "2013-09-20T08:45:18.220Z"}, {"lat": "44.144511", "lng": "9.663258", "elevation": "202.0", "time": "2013-09-20T08:45:27.262Z"}, {"lat": "44.144503", "lng": "9.663259", "elevation": "200.39999389648438", "time": "2013-09-20T08:45:28.141Z"}, {"lat": "44.144419", "lng": "9.663262", "elevation": "198.3000030517578", "time": "2013-09-20T08:45:33.164Z"}, {"lat": "44.144404", "lng": "9.663262", "elevation": "197.3000030517578", "time": "2013-09-20T08:45:34.204Z"}, {"lat": "44.144364", "lng": "9.663282", "elevation": "198.3000030517578", "time": "2013-09-20T08:45:42.142Z"}, {"lat": "44.144366", "lng": "9.663283", "elevation": "198.10000610351563", "time": "2013-09-20T08:45:43.149Z"}, {"lat": "44.144362", "lng": "9.663275", "elevation": "199.3000030517578", "time": "2013-09-20T08:46:03.152Z"}, {"lat": "44.144358", "lng": "9.663284", "elevation": "199.1999969482422", "time": "2013-09-20T08:46:04.142Z"}, {"lat": "44.144319", "lng": "9.663392", "elevation": "201.60000610351563", "time": "2013-09-20T08:46:12.160Z"}, {"lat": "44.144313", "lng": "9.663404", "elevation": "201.0", "time": "2013-09-20T08:46:13.153Z"}, {"lat": "44.144264", "lng": "9.663501", "elevation": "204.89999389648438", "time": "2013-09-20T08:46:20.144Z"}, {"lat": "44.144256", "lng": "9.663513", "elevation": "206.60000610351563", "time": "2013-09-20T08:46:21.170Z"}, {"lat": "44.144207", "lng": "9.663617", "elevation": "207.89999389648438", "time": "2013-09-20T08:46:31.257Z"}, {"lat": "44.144203", "lng": "9.663625", "elevation": "208.6999969482422", "time": "2013-09-20T08:46:32.221Z"}, {"lat": "44.144194", "lng": "9.6637", "elevation": "210.10000610351563", "time": "2013-09-20T08:46:44.148Z"}, {"lat": "44.144195", "lng": "9.663701", "elevation": "210.0", "time": "2013-09-20T08:46:45.162Z"}, {"lat": "44.144193", "lng": "9.663706", "elevation": "210.0", "time": "2013-09-20T08:47:02.176Z"}, {"lat": "44.144194", "lng": "9.663712", "elevation": "209.39999389648438", "time": "2013-09-20T08:47:03.180Z"}, {"lat": "44.144242", "lng": "9.663813", "elevation": "205.8000030517578", "time": "2013-09-20T08:47:19.246Z"}, {"lat": "44.144247", "lng": "9.663822", "elevation": "205.1999969482422", "time": "2013-09-20T08:47:20.183Z"}, {"lat": "44.144316", "lng": "9.663899", "elevation": "202.10000610351563", "time": "2013-09-20T08:47:34.231Z"}, {"lat": "44.14432", "lng": "9.663909", "elevation": "201.89999389648438", "time": "2013-09-20T08:47:35.229Z"}, {"lat": "44.144355", "lng": "9.66397", "elevation": "205.89999389648438", "time": "2013-09-20T08:47:43.176Z"}, {"lat": "44.144354", "lng": "9.663968", "elevation": "205.8000030517578", "time": "2013-09-20T08:47:44.172Z"}, {"lat": "44.144359", "lng": "9.663989", "elevation": "207.8000030517578", "time": "2013-09-20T08:47:53.213Z"}, {"lat": "44.14436", "lng": "9.663996", "elevation": "207.89999389648438", "time": "2013-09-20T08:47:54.162Z"}, {"lat": "44.144404", "lng": "9.664094", "elevation": "210.10000610351563", "time": "2013-09-20T08:48:01.203Z"}, {"lat": "44.14441", "lng": "9.664112", "elevation": "209.89999389648438", "time": "2013-09-20T08:48:02.167Z"}, {"lat": "44.144445", "lng": "9.664217", "elevation": "208.39999389648438", "time": "2013-09-20T08:48:09.225Z"}, {"lat": "44.14445", "lng": "9.664226", "elevation": "207.39999389648438", "time": "2013-09-20T08:48:10.169Z"}, {"lat": "44.14451", "lng": "9.664318", "elevation": "207.6999969482422", "time": "2013-09-20T08:48:19.190Z"}, {"lat": "44.144516", "lng": "9.664334", "elevation": "206.0", "time": "2013-09-20T08:48:20.177Z"}, {"lat": "44.144565", "lng": "9.664426", "elevation": "205.0", "time": "2013-09-20T08:48:27.171Z"}, {"lat": "44.144574", "lng": "9.664434", "elevation": "205.10000610351563", "time": "2013-09-20T08:48:28.180Z"}, {"lat": "44.144609", "lng": "9.664543", "elevation": "206.6999969482422", "time": "2013-09-20T08:48:40.184Z"}, {"lat": "44.14461", "lng": "9.664554", "elevation": "206.39999389648438", "time": "2013-09-20T08:48:41.182Z"}, {"lat": "44.144638", "lng": "9.664672", "elevation": "205.10000610351563", "time": "2013-09-20T08:48:51.188Z"}, {"lat": "44.144642", "lng": "9.664682", "elevation": "205.60000610351563", "time": "2013-09-20T08:48:52.230Z"}, {"lat": "44.144682", "lng": "9.664781", "elevation": "205.8000030517578", "time": "2013-09-20T08:49:02.254Z"}, {"lat": "44.144687", "lng": "9.664793", "elevation": "206.0", "time": "2013-09-20T08:49:03.262Z"}, {"lat": "44.144653", "lng": "9.664906", "elevation": "206.60000610351563", "time": "2013-09-20T08:49:15.287Z"}, {"lat": "44.14465", "lng": "9.664912", "elevation": "207.10000610351563", "time": "2013-09-20T08:49:16.261Z"}, {"lat": "44.144651", "lng": "9.664916", "elevation": "205.89999389648438", "time": "2013-09-20T08:49:18.271Z"}, {"lat": "44.144656", "lng": "9.664914", "elevation": "205.89999389648438", "time": "2013-09-20T08:49:19.343Z"}, {"lat": "44.144661", "lng": "9.664911", "elevation": "206.0", "time": "2013-09-20T08:49:20.304Z"}, {"lat": "44.144685", "lng": "9.664912", "elevation": "205.89999389648438", "time": "2013-09-20T08:49:28.388Z"}, {"lat": "44.144686", "lng": "9.664914", "elevation": "206.0", "time": "2013-09-20T08:49:29.371Z"}, {"lat": "44.144687", "lng": "9.66492", "elevation": "205.89999389648438", "time": "2013-09-20T08:49:35.323Z"}, {"lat": "44.144691", "lng": "9.664926", "elevation": "205.39999389648438", "time": "2013-09-20T08:49:36.247Z"}, {"lat": "44.144753", "lng": "9.665007", "elevation": "203.6999969482422", "time": "2013-09-20T08:49:42.194Z"}, {"lat": "44.144764", "lng": "9.665024", "elevation": "203.89999389648438", "time": "2013-09-20T08:49:43.371Z"}, {"lat": "44.144819", "lng": "9.66512", "elevation": "204.10000610351563", "time": "2013-09-20T08:49:51.386Z"}, {"lat": "44.14482", "lng": "9.665126", "elevation": "204.3000030517578", "time": "2013-09-20T08:49:52.321Z"}, {"lat": "44.144856", "lng": "9.665239", "elevation": "205.89999389648438", "time": "2013-09-20T08:50:03.402Z"}, {"lat": "44.144859", "lng": "9.665241", "elevation": "205.60000610351563", "time": "2013-09-20T08:50:04.370Z"}, {"lat": "44.144862", "lng": "9.665246", "elevation": "205.5", "time": "2013-09-20T08:50:07.377Z"}, {"lat": "44.144862", "lng": "9.665247", "elevation": "205.5", "time": "2013-09-20T08:50:08.322Z"}, {"lat": "44.144864", "lng": "9.665254", "elevation": "206.1999969482422", "time": "2013-09-20T08:50:17.332Z"}, {"lat": "44.144867", "lng": "9.665261", "elevation": "206.10000610351563", "time": "2013-09-20T08:50:18.349Z"}, {"lat": "44.144931", "lng": "9.665342", "elevation": "207.6999969482422", "time": "2013-09-20T08:50:23.347Z"}, {"lat": "44.144945", "lng": "9.66536", "elevation": "208.0", "time": "2013-09-20T08:50:24.325Z"}, {"lat": "44.144995", "lng": "9.665457", "elevation": "206.39999389648438", "time": "2013-09-20T08:50:30.244Z"}, {"lat": "44.144997", "lng": "9.665466", "elevation": "206.3000030517578", "time": "2013-09-20T08:50:31.187Z"}, {"lat": "44.144991", "lng": "9.6655", "elevation": "206.1999969482422", "time": "2013-09-20T08:50:41.277Z"}, {"lat": "44.144991", "lng": "9.665502", "elevation": "205.8000030517578", "time": "2013-09-20T08:50:42.244Z"}, {"lat": "44.144995", "lng": "9.665519", "elevation": "204.1999969482422", "time": "2013-09-20T08:50:54.344Z"}, {"lat": "44.144995", "lng": "9.665528", "elevation": "204.1999969482422", "time": "2013-09-20T08:50:55.360Z"}, {"lat": "44.144992", "lng": "9.665644", "elevation": "206.8000030517578", "time": "2013-09-20T08:51:02.176Z"}, {"lat": "44.14499", "lng": "9.665659", "elevation": "206.6999969482422", "time": "2013-09-20T08:51:03.176Z"}, {"lat": "44.145013", "lng": "9.665772", "elevation": "204.60000610351563", "time": "2013-09-20T08:51:12.336Z"}, {"lat": "44.145022", "lng": "9.665786", "elevation": "204.10000610351563", "time": "2013-09-20T08:51:13.305Z"}, {"lat": "44.14507", "lng": "9.665875", "elevation": "204.3000030517578", "time": "2013-09-20T08:51:20.280Z"}, {"lat": "44.145072", "lng": "9.665891", "elevation": "202.89999389648438", "time": "2013-09-20T08:51:21.363Z"}, {"lat": "44.145067", "lng": "9.666001", "elevation": "197.8000030517578", "time": "2013-09-20T08:51:37.323Z"}, {"lat": "44.145074", "lng": "9.666025", "elevation": "197.5", "time": "2013-09-20T08:51:38.322Z"}, {"lat": "44.145099", "lng": "9.666122", "elevation": "196.3000030517578", "time": "2013-09-20T08:51:41.330Z"}, {"lat": "44.145112", "lng": "9.666149", "elevation": "196.3000030517578", "time": "2013-09-20T08:51:42.355Z"}, {"lat": "44.14516", "lng": "9.666228", "elevation": "197.6999969482422", "time": "2013-09-20T08:51:46.256Z"}, {"lat": "44.14517", "lng": "9.666247", "elevation": "197.3000030517578", "time": "2013-09-20T08:51:47.227Z"}, {"lat": "44.145223", "lng": "9.666331", "elevation": "199.89999389648438", "time": "2013-09-20T08:51:54.211Z"}, {"lat": "44.145231", "lng": "9.666343", "elevation": "201.0", "time": "2013-09-20T08:51:55.178Z"}, {"lat": "44.145287", "lng": "9.666436", "elevation": "202.60000610351563", "time": "2013-09-20T08:52:02.194Z"}, {"lat": "44.145294", "lng": "9.666447", "elevation": "202.89999389648438", "time": "2013-09-20T08:52:03.228Z"}, {"lat": "44.145377", "lng": "9.666465", "elevation": "201.0", "time": "2013-09-20T08:52:13.181Z"}, {"lat": "44.145386", "lng": "9.666461", "elevation": "201.10000610351563", "time": "2013-09-20T08:52:14.212Z"}, {"lat": "44.14542", "lng": "9.666575", "elevation": "199.1999969482422", "time": "2013-09-20T08:52:29.348Z"}, {"lat": "44.145421", "lng": "9.666594", "elevation": "199.0", "time": "2013-09-20T08:52:30.327Z"}, {"lat": "44.145417", "lng": "9.666709", "elevation": "195.39999389648438", "time": "2013-09-20T08:52:36.199Z"}, {"lat": "44.145418", "lng": "9.666721", "elevation": "196.10000610351563", "time": "2013-09-20T08:52:37.197Z"}, {"lat": "44.145423", "lng": "9.666843", "elevation": "195.6999969482422", "time": "2013-09-20T08:52:49.192Z"}, {"lat": "44.145426", "lng": "9.666855", "elevation": "195.10000610351563", "time": "2013-09-20T08:52:50.233Z"}, {"lat": "44.145455", "lng": "9.666967", "elevation": "194.1999969482422", "time": "2013-09-20T08:52:58.191Z"}, {"lat": "44.145459", "lng": "9.66698", "elevation": "194.0", "time": "2013-09-20T08:52:59.184Z"}, {"lat": "44.145496", "lng": "9.667082", "elevation": "191.10000610351563", "time": "2013-09-20T08:53:09.183Z"}, {"lat": "44.1455", "lng": "9.667098", "elevation": "191.1999969482422", "time": "2013-09-20T08:53:10.200Z"}, {"lat": "44.145552", "lng": "9.667184", "elevation": "191.8000030517578", "time": "2013-09-20T08:53:16.329Z"}, {"lat": "44.145557", "lng": "9.667196", "elevation": "191.8000030517578", "time": "2013-09-20T08:53:17.356Z"}, {"lat": "44.145562", "lng": "9.667214", "elevation": "189.60000610351563", "time": "2013-09-20T08:53:22.291Z"}, {"lat": "44.14556", "lng": "9.667212", "elevation": "189.6999969482422", "time": "2013-09-20T08:53:23.241Z"}, {"lat": "44.145553", "lng": "9.66721", "elevation": "188.6999969482422", "time": "2013-09-20T08:53:50.175Z"}, {"lat": "44.145559", "lng": "9.66721", "elevation": "189.1999969482422", "time": "2013-09-20T08:53:51.175Z"}, {"lat": "44.145641", "lng": "9.667257", "elevation": "192.10000610351563", "time": "2013-09-20T08:53:58.197Z"}, {"lat": "44.14565", "lng": "9.667267", "elevation": "192.5", "time": "2013-09-20T08:53:59.181Z"}, {"lat": "44.145691", "lng": "9.66735", "elevation": "193.1999969482422", "time": "2013-09-20T08:54:05.205Z"}, {"lat": "44.145695", "lng": "9.667379", "elevation": "193.39999389648438", "time": "2013-09-20T08:54:06.190Z"}, {"lat": "44.145706", "lng": "9.66749", "elevation": "194.60000610351563", "time": "2013-09-20T08:54:09.182Z"}, {"lat": "44.145712", "lng": "9.667534", "elevation": "195.3000030517578", "time": "2013-09-20T08:54:10.213Z"}, {"lat": "44.145739", "lng": "9.667573", "elevation": "194.89999389648438", "time": "2013-09-20T08:54:19.207Z"}, {"lat": "44.145739", "lng": "9.667574", "elevation": "194.0", "time": "2013-09-20T08:54:20.196Z"}, {"lat": "44.14574", "lng": "9.667582", "elevation": "195.39999389648438", "time": "2013-09-20T08:54:22.213Z"}, {"lat": "44.145741", "lng": "9.667587", "elevation": "194.5", "time": "2013-09-20T08:54:23.191Z"}, {"lat": "44.145733", "lng": "9.667644", "elevation": "198.1999969482422", "time": "2013-09-20T08:54:32.207Z"}, {"lat": "44.145733", "lng": "9.667643", "elevation": "198.89999389648438", "time": "2013-09-20T08:54:33.214Z"}, {"lat": "44.145739", "lng": "9.667633", "elevation": "198.10000610351563", "time": "2013-09-20T08:54:42.192Z"}, {"lat": "44.145741", "lng": "9.667637", "elevation": "198.39999389648438", "time": "2013-09-20T08:54:43.214Z"}, {"lat": "44.145724", "lng": "9.667754", "elevation": "199.8000030517578", "time": "2013-09-20T08:54:52.188Z"}, {"lat": "44.145723", "lng": "9.667775", "elevation": "198.5", "time": "2013-09-20T08:54:53.202Z"}, {"lat": "44.145703", "lng": "9.667889", "elevation": "197.0", "time": "2013-09-20T08:55:07.208Z"}, {"lat": "44.145707", "lng": "9.667901", "elevation": "196.6999969482422", "time": "2013-09-20T08:55:08.242Z"}, {"lat": "44.14571", "lng": "9.667922", "elevation": "195.6999969482422", "time": "2013-09-20T08:55:13.217Z"}, {"lat": "44.145707", "lng": "9.667921", "elevation": "196.6999969482422", "time": "2013-09-20T08:55:14.251Z"}, {"lat": "44.145704", "lng": "9.66792", "elevation": "196.1999969482422", "time": "2013-09-20T08:55:15.210Z"}, {"lat": "44.1457", "lng": "9.667919", "elevation": "196.60000610351563", "time": "2013-09-20T08:55:16.230Z"}, {"lat": "44.145617", "lng": "9.667918", "elevation": "196.3000030517578", "time": "2013-09-20T08:55:29.211Z"}, {"lat": "44.145603", "lng": "9.667908", "elevation": "197.39999389648438", "time": "2013-09-20T08:55:30.197Z"}, {"lat": "44.145516", "lng": "9.667888", "elevation": "197.10000610351563", "time": "2013-09-20T08:55:37.203Z"}, {"lat": "44.145508", "lng": "9.667883", "elevation": "198.60000610351563", "time": "2013-09-20T08:55:38.212Z"}, {"lat": "44.14545", "lng": "9.667852", "elevation": "196.8000030517578", "time": "2013-09-20T08:55:56.193Z"}, {"lat": "44.14545", "lng": "9.667852", "elevation": "197.0", "time": "2013-09-20T08:55:57.198Z"}, {"lat": "44.145443", "lng": "9.667863", "elevation": "195.6999969482422", "time": "2013-09-20T08:56:10.210Z"}, {"lat": "44.145437", "lng": "9.667863", "elevation": "198.1999969482422", "time": "2013-09-20T08:56:11.230Z"}, {"lat": "44.145349", "lng": "9.667869", "elevation": "197.10000610351563", "time": "2013-09-20T08:56:18.200Z"}, {"lat": "44.145335", "lng": "9.66787", "elevation": "198.0", "time": "2013-09-20T08:56:19.231Z"}, {"lat": "44.145254", "lng": "9.667841", "elevation": "193.89999389648438", "time": "2013-09-20T08:56:25.279Z"}, {"lat": "44.145241", "lng": "9.667831", "elevation": "192.6999969482422", "time": "2013-09-20T08:56:26.230Z"}, {"lat": "44.145155", "lng": "9.667803", "elevation": "194.10000610351563", "time": "2013-09-20T08:56:32.207Z"}, {"lat": "44.145141", "lng": "9.667805", "elevation": "194.3000030517578", "time": "2013-09-20T08:56:33.233Z"}, {"lat": "44.145086", "lng": "9.667807", "elevation": "191.8000030517578", "time": "2013-09-20T08:56:46.216Z"}, {"lat": "44.145085", "lng": "9.667808", "elevation": "191.8000030517578", "time": "2013-09-20T08:56:47.207Z"}, {"lat": "44.145082", "lng": "9.667807", "elevation": "192.1999969482422", "time": "2013-09-20T08:56:48.217Z"}, {"lat": "44.145076", "lng": "9.667807", "elevation": "192.39999389648438", "time": "2013-09-20T08:56:49.217Z"}, {"lat": "44.144992", "lng": "9.667778", "elevation": "194.0", "time": "2013-09-20T08:56:55.208Z"}, {"lat": "44.144977", "lng": "9.667771", "elevation": "194.10000610351563", "time": "2013-09-20T08:56:56.234Z"}, {"lat": "44.1449", "lng": "9.66773", "elevation": "195.39999389648438", "time": "2013-09-20T08:57:02.217Z"}, {"lat": "44.144888", "lng": "9.667724", "elevation": "196.10000610351563", "time": "2013-09-20T08:57:03.267Z"}, {"lat": "44.144801", "lng": "9.667719", "elevation": "193.3000030517578", "time": "2013-09-20T08:57:15.224Z"}, {"lat": "44.144792", "lng": "9.667717", "elevation": "193.10000610351563", "time": "2013-09-20T08:57:16.310Z"}, {"lat": "44.144702", "lng": "9.667699", "elevation": "189.5", "time": "2013-09-20T08:57:30.220Z"}, {"lat": "44.144698", "lng": "9.667704", "elevation": "189.5", "time": "2013-09-20T08:57:31.220Z"}, {"lat": "44.144612", "lng": "9.667714", "elevation": "184.1999969482422", "time": "2013-09-20T08:57:41.244Z"}, {"lat": "44.144597", "lng": "9.667713", "elevation": "184.39999389648438", "time": "2013-09-20T08:57:42.215Z"}, {"lat": "44.144547", "lng": "9.667816", "elevation": "194.1999969482422", "time": "2013-09-20T08:57:57.230Z"}, {"lat": "44.144544", "lng": "9.667823", "elevation": "195.39999389648438", "time": "2013-09-20T08:57:58.256Z"}, {"lat": "44.144581", "lng": "9.667931", "elevation": "200.8000030517578", "time": "2013-09-20T08:58:12.304Z"}, {"lat": "44.144579", "lng": "9.667938", "elevation": "201.10000610351563", "time": "2013-09-20T08:58:13.264Z"}, {"lat": "44.144543", "lng": "9.668047", "elevation": "200.6999969482422", "time": "2013-09-20T08:58:22.288Z"}, {"lat": "44.144541", "lng": "9.668063", "elevation": "201.10000610351563", "time": "2013-09-20T08:58:23.381Z"}, {"lat": "44.144542", "lng": "9.668181", "elevation": "200.39999389648438", "time": "2013-09-20T08:58:32.226Z"}, {"lat": "44.144542", "lng": "9.66819", "elevation": "201.89999389648438", "time": "2013-09-20T08:58:33.213Z"}, {"lat": "44.144476", "lng": "9.668256", "elevation": "198.6999969482422", "time": "2013-09-20T08:58:44.323Z"}, {"lat": "44.14447", "lng": "9.668272", "elevation": "199.3000030517578", "time": "2013-09-20T08:58:45.291Z"}, {"lat": "44.144473", "lng": "9.668395", "elevation": "207.10000610351563", "time": "2013-09-20T08:58:59.284Z"}, {"lat": "44.144475", "lng": "9.668399", "elevation": "207.5", "time": "2013-09-20T08:59:00.355Z"}, {"lat": "44.144447", "lng": "9.668515", "elevation": "205.5", "time": "2013-09-20T08:59:12.285Z"}, {"lat": "44.144445", "lng": "9.668528", "elevation": "205.8000030517578", "time": "2013-09-20T08:59:13.231Z"}, {"lat": "44.144438", "lng": "9.668644", "elevation": "205.3000030517578", "time": "2013-09-20T08:59:25.359Z"}, {"lat": "44.144429", "lng": "9.668653", "elevation": "205.3000030517578", "time": "2013-09-20T08:59:26.367Z"}, {"lat": "44.144408", "lng": "9.668772", "elevation": "207.5", "time": "2013-09-20T08:59:39.319Z"}, {"lat": "44.144411", "lng": "9.668783", "elevation": "208.10000610351563", "time": "2013-09-20T08:59:40.365Z"}, {"lat": "44.144481", "lng": "9.668861", "elevation": "211.1999969482422", "time": "2013-09-20T08:59:52.223Z"}, {"lat": "44.144485", "lng": "9.66887", "elevation": "211.39999389648438", "time": "2013-09-20T08:59:53.240Z"}, {"lat": "44.144481", "lng": "9.668992", "elevation": "210.39999389648438", "time": "2013-09-20T09:00:04.345Z"}, {"lat": "44.144482", "lng": "9.669003", "elevation": "210.60000610351563", "time": "2013-09-20T09:00:05.306Z"}, {"lat": "44.144454", "lng": "9.66906", "elevation": "210.39999389648438", "time": "2013-09-20T09:00:15.349Z"}, {"lat": "44.144453", "lng": "9.66906", "elevation": "210.3000030517578", "time": "2013-09-20T09:00:16.373Z"}, {"lat": "44.144451", "lng": "9.669059", "elevation": "210.1999969482422", "time": "2013-09-20T09:00:17.328Z"}, {"lat": "44.144447", "lng": "9.669058", "elevation": "210.1999969482422", "time": "2013-09-20T09:00:18.393Z"}, {"lat": "44.144438", "lng": "9.669054", "elevation": "210.10000610351563", "time": "2013-09-20T09:00:22.266Z"}, {"lat": "44.144438", "lng": "9.669054", "elevation": "210.0", "time": "2013-09-20T09:00:23.234Z"}, {"lat": "44.144439", "lng": "9.669063", "elevation": "210.1999969482422", "time": "2013-09-20T09:00:41.226Z"}, {"lat": "44.144439", "lng": "9.669074", "elevation": "210.60000610351563", "time": "2013-09-20T09:00:42.241Z"}, {"lat": "44.144431", "lng": "9.669184", "elevation": "213.1999969482422", "time": "2013-09-20T09:00:48.323Z"}, {"lat": "44.144428", "lng": "9.669204", "elevation": "213.6999969482422", "time": "2013-09-20T09:00:49.323Z"}, {"lat": "44.144437", "lng": "9.669318", "elevation": "212.39999389648438", "time": "2013-09-20T09:00:54.282Z"}, {"lat": "44.14444", "lng": "9.669341", "elevation": "212.0", "time": "2013-09-20T09:00:55.227Z"}, {"lat": "44.144402", "lng": "9.669447", "elevation": "211.3000030517578", "time": "2013-09-20T09:01:02.394Z"}, {"lat": "44.144399", "lng": "9.669458", "elevation": "211.3000030517578", "time": "2013-09-20T09:01:03.344Z"}, {"lat": "44.144371", "lng": "9.669565", "elevation": "213.89999389648438", "time": "2013-09-20T09:01:13.236Z"}, {"lat": "44.144368", "lng": "9.669583", "elevation": "214.8000030517578", "time": "2013-09-20T09:01:14.244Z"}, {"lat": "44.144391", "lng": "9.669694", "elevation": "215.0", "time": "2013-09-20T09:01:21.336Z"}, {"lat": "44.144397", "lng": "9.669703", "elevation": "214.6999969482422", "time": "2013-09-20T09:01:22.334Z"}, {"lat": "44.144386", "lng": "9.66982", "elevation": "215.1999969482422", "time": "2013-09-20T09:01:31.282Z"}, {"lat": "44.144379", "lng": "9.669826", "elevation": "216.3000030517578", "time": "2013-09-20T09:01:32.321Z"}, {"lat": "44.144351", "lng": "9.669856", "elevation": "217.0", "time": "2013-09-20T09:01:41.344Z"}, {"lat": "44.144351", "lng": "9.669857", "elevation": "216.6999969482422", "time": "2013-09-20T09:01:42.295Z"}, {"lat": "44.144337", "lng": "9.66986", "elevation": "214.39999389648438", "time": "2013-09-20T09:01:55.249Z"}, {"lat": "44.144331", "lng": "9.669859", "elevation": "213.3000030517578", "time": "2013-09-20T09:01:56.251Z"}, {"lat": "44.144244", "lng": "9.669859", "elevation": "210.6999969482422", "time": "2013-09-20T09:02:04.326Z"}, {"lat": "44.144229", "lng": "9.669855", "elevation": "209.6999969482422", "time": "2013-09-20T09:02:05.266Z"}, {"lat": "44.144145", "lng": "9.669813", "elevation": "210.3000030517578", "time": "2013-09-20T09:02:12.254Z"}, {"lat": "44.144133", "lng": "9.669806", "elevation": "211.60000610351563", "time": "2013-09-20T09:02:13.307Z"}, {"lat": "44.144084", "lng": "9.669726", "elevation": "211.8000030517578", "time": "2013-09-20T09:02:18.230Z"}, {"lat": "44.144075", "lng": "9.669703", "elevation": "211.60000610351563", "time": "2013-09-20T09:02:19.260Z"}, {"lat": "44.144018", "lng": "9.669627", "elevation": "213.5", "time": "2013-09-20T09:02:24.285Z"}, {"lat": "44.144005", "lng": "9.669616", "elevation": "214.3000030517578", "time": "2013-09-20T09:02:25.259Z"}, {"lat": "44.143925", "lng": "9.669578", "elevation": "214.0", "time": "2013-09-20T09:02:30.279Z"}, {"lat": "44.143911", "lng": "9.669575", "elevation": "213.5", "time": "2013-09-20T09:02:31.326Z"}, {"lat": "44.143833", "lng": "9.669571", "elevation": "214.3000030517578", "time": "2013-09-20T09:02:37.235Z"}, {"lat": "44.143818", "lng": "9.669571", "elevation": "214.10000610351563", "time": "2013-09-20T09:02:38.282Z"}, {"lat": "44.143755", "lng": "9.669483", "elevation": "213.1999969482422", "time": "2013-09-20T09:02:46.284Z"}, {"lat": "44.143748", "lng": "9.669477", "elevation": "212.3000030517578", "time": "2013-09-20T09:02:47.326Z"}, {"lat": "44.143667", "lng": "9.669444", "elevation": "211.1999969482422", "time": "2013-09-20T09:02:57.271Z"}, {"lat": "44.143659", "lng": "9.669438", "elevation": "211.39999389648438", "time": "2013-09-20T09:02:58.247Z"}, {"lat": "44.143598", "lng": "9.669348", "elevation": "216.1999969482422", "time": "2013-09-20T09:03:06.234Z"}, {"lat": "44.143589", "lng": "9.669334", "elevation": "217.0", "time": "2013-09-20T09:03:07.235Z"}, {"lat": "44.143531", "lng": "9.669243", "elevation": "218.8000030517578", "time": "2013-09-20T09:03:13.238Z"}, {"lat": "44.143523", "lng": "9.66923", "elevation": "219.0", "time": "2013-09-20T09:03:14.235Z"}, {"lat": "44.143485", "lng": "9.669128", "elevation": "219.1999969482422", "time": "2013-09-20T09:03:22.241Z"}, {"lat": "44.143479", "lng": "9.66912", "elevation": "219.10000610351563", "time": "2013-09-20T09:03:23.255Z"}, {"lat": "44.143393", "lng": "9.669141", "elevation": "220.3000030517578", "time": "2013-09-20T09:03:42.332Z"}, {"lat": "44.143389", "lng": "9.66914", "elevation": "220.8000030517578", "time": "2013-09-20T09:03:43.343Z"}, {"lat": "44.143316", "lng": "9.669112", "elevation": "224.60000610351563", "time": "2013-09-20T09:03:57.267Z"}, {"lat": "44.143317", "lng": "9.669111", "elevation": "224.6999969482422", "time": "2013-09-20T09:03:58.315Z"}, {"lat": "44.143317", "lng": "9.669118", "elevation": "224.10000610351563", "time": "2013-09-20T09:04:03.241Z"}, {"lat": "44.143314", "lng": "9.669121", "elevation": "224.1999969482422", "time": "2013-09-20T09:04:04.306Z"}, {"lat": "44.143311", "lng": "9.669125", "elevation": "224.6999969482422", "time": "2013-09-20T09:04:06.251Z"}, {"lat": "44.14331", "lng": "9.669126", "elevation": "225.10000610351563", "time": "2013-09-20T09:04:07.261Z"}, {"lat": "44.143303", "lng": "9.66912", "elevation": "225.39999389648438", "time": "2013-09-20T09:04:14.248Z"}, {"lat": "44.1433", "lng": "9.669122", "elevation": "224.1999969482422", "time": "2013-09-20T09:04:15.253Z"}, {"lat": "44.143214", "lng": "9.669147", "elevation": "221.60000610351563", "time": "2013-09-20T09:04:23.285Z"}, {"lat": "44.143201", "lng": "9.669156", "elevation": "220.5", "time": "2013-09-20T09:04:24.292Z"}, {"lat": "44.143132", "lng": "9.669228", "elevation": "218.8000030517578", "time": "2013-09-20T09:04:31.331Z"}, {"lat": "44.143125", "lng": "9.669245", "elevation": "219.1999969482422", "time": "2013-09-20T09:04:32.334Z"}, {"lat": "44.143048", "lng": "9.669309", "elevation": "216.0", "time": "2013-09-20T09:04:40.320Z"}, {"lat": "44.143039", "lng": "9.669316", "elevation": "217.39999389648438", "time": "2013-09-20T09:04:41.273Z"}, {"lat": "44.14297", "lng": "9.669391", "elevation": "220.1999969482422", "time": "2013-09-20T09:04:52.254Z"}, {"lat": "44.142966", "lng": "9.669397", "elevation": "220.3000030517578", "time": "2013-09-20T09:04:53.262Z"}, {"lat": "44.14292", "lng": "9.669493", "elevation": "231.0", "time": "2013-09-20T09:05:08.249Z"}, {"lat": "44.142916", "lng": "9.669504", "elevation": "231.6999969482422", "time": "2013-09-20T09:05:09.270Z"}, {"lat": "44.142854", "lng": "9.669583", "elevation": "229.3000030517578", "time": "2013-09-20T09:05:17.264Z"}, {"lat": "44.142843", "lng": "9.669591", "elevation": "229.0", "time": "2013-09-20T09:05:18.267Z"}, {"lat": "44.142811", "lng": "9.669699", "elevation": "229.1999969482422", "time": "2013-09-20T09:05:38.291Z"}, {"lat": "44.142812", "lng": "9.6697", "elevation": "229.39999389648438", "time": "2013-09-20T09:05:39.265Z"}, {"lat": "44.142807", "lng": "9.669704", "elevation": "229.10000610351563", "time": "2013-09-20T09:05:53.343Z"}, {"lat": "44.142802", "lng": "9.66971", "elevation": "228.60000610351563", "time": "2013-09-20T09:05:54.266Z"}, {"lat": "44.142739", "lng": "9.669788", "elevation": "226.89999389648438", "time": "2013-09-20T09:06:00.365Z"}, {"lat": "44.142725", "lng": "9.669803", "elevation": "225.60000610351563", "time": "2013-09-20T09:06:01.348Z"}, {"lat": "44.142665", "lng": "9.669875", "elevation": "224.6999969482422", "time": "2013-09-20T09:06:06.260Z"}, {"lat": "44.142658", "lng": "9.669893", "elevation": "225.39999389648438", "time": "2013-09-20T09:06:07.262Z"}, {"lat": "44.142614", "lng": "9.669987", "elevation": "223.60000610351563", "time": "2013-09-20T09:06:12.262Z"}, {"lat": "44.1426", "lng": "9.670006", "elevation": "223.5", "time": "2013-09-20T09:06:13.255Z"}, {"lat": "44.142532", "lng": "9.670084", "elevation": "221.60000610351563", "time": "2013-09-20T09:06:18.269Z"}, {"lat": "44.142521", "lng": "9.670096", "elevation": "221.0", "time": "2013-09-20T09:06:19.292Z"}, {"lat": "44.142444", "lng": "9.670138", "elevation": "220.39999389648438", "time": "2013-09-20T09:06:28.263Z"}, {"lat": "44.142433", "lng": "9.670138", "elevation": "219.5", "time": "2013-09-20T09:06:29.275Z"}, {"lat": "44.142349", "lng": "9.67018", "elevation": "215.10000610351563", "time": "2013-09-20T09:06:37.272Z"}, {"lat": "44.14234", "lng": "9.670191", "elevation": "215.0", "time": "2013-09-20T09:06:38.255Z"}, {"lat": "44.142282", "lng": "9.670284", "elevation": "212.60000610351563", "time": "2013-09-20T09:06:47.259Z"}, {"lat": "44.142278", "lng": "9.670289", "elevation": "211.6999969482422", "time": "2013-09-20T09:06:48.281Z"}, {"lat": "44.142205", "lng": "9.670358", "elevation": "212.3000030517578", "time": "2013-09-20T09:06:58.282Z"}, {"lat": "44.142197", "lng": "9.670374", "elevation": "212.0", "time": "2013-09-20T09:06:59.264Z"}, {"lat": "44.142145", "lng": "9.670464", "elevation": "211.60000610351563", "time": "2013-09-20T09:07:07.267Z"}, {"lat": "44.142132", "lng": "9.670468", "elevation": "211.89999389648438", "time": "2013-09-20T09:07:08.264Z"}, {"lat": "44.142055", "lng": "9.670509", "elevation": "208.5", "time": "2013-09-20T09:07:19.283Z"}, {"lat": "44.142045", "lng": "9.670511", "elevation": "207.8000030517578", "time": "2013-09-20T09:07:20.310Z"}, {"lat": "44.141963", "lng": "9.670544", "elevation": "205.1999969482422", "time": "2013-09-20T09:07:28.260Z"}, {"lat": "44.141956", "lng": "9.670557", "elevation": "204.89999389648438", "time": "2013-09-20T09:07:29.274Z"}, {"lat": "44.141916", "lng": "9.670662", "elevation": "203.6999969482422", "time": "2013-09-20T09:07:37.269Z"}, {"lat": "44.141911", "lng": "9.670673", "elevation": "204.0", "time": "2013-09-20T09:07:38.292Z"}, {"lat": "44.141832", "lng": "9.670726", "elevation": "203.5", "time": "2013-09-20T09:07:56.270Z"}, {"lat": "44.141829", "lng": "9.670736", "elevation": "203.89999389648438", "time": "2013-09-20T09:07:57.278Z"}, {"lat": "44.141775", "lng": "9.67069", "elevation": "208.89999389648438", "time": "2013-09-20T09:08:14.343Z"}, {"lat": "44.141775", "lng": "9.670689", "elevation": "208.6999969482422", "time": "2013-09-20T09:08:15.377Z"}, {"lat": "44.141772", "lng": "9.670694", "elevation": "208.89999389648438", "time": "2013-09-20T09:08:29.334Z"}, {"lat": "44.141767", "lng": "9.6707", "elevation": "209.8000030517578", "time": "2013-09-20T09:08:30.313Z"}, {"lat": "44.141695", "lng": "9.670774", "elevation": "209.0", "time": "2013-09-20T09:08:36.290Z"}, {"lat": "44.141682", "lng": "9.670793", "elevation": "206.3000030517578", "time": "2013-09-20T09:08:37.303Z"}, {"lat": "44.141676", "lng": "9.670903", "elevation": "206.3000030517578", "time": "2013-09-20T09:08:42.272Z"}, {"lat": "44.141676", "lng": "9.670921", "elevation": "206.5", "time": "2013-09-20T09:08:43.264Z"}, {"lat": "44.141665", "lng": "9.671042", "elevation": "209.10000610351563", "time": "2013-09-20T09:08:51.284Z"}, {"lat": "44.141658", "lng": "9.671052", "elevation": "208.60000610351563", "time": "2013-09-20T09:08:52.281Z"}, {"lat": "44.141598", "lng": "9.671141", "elevation": "207.5", "time": "2013-09-20T09:09:01.265Z"}, {"lat": "44.141586", "lng": "9.671158", "elevation": "207.8000030517578", "time": "2013-09-20T09:09:02.296Z"}, {"lat": "44.141525", "lng": "9.671237", "elevation": "208.8000030517578", "time": "2013-09-20T09:09:07.275Z"}, {"lat": "44.141513", "lng": "9.67125", "elevation": "209.1999969482422", "time": "2013-09-20T09:09:08.265Z"}, {"lat": "44.141455", "lng": "9.671324", "elevation": "210.39999389648438", "time": "2013-09-20T09:09:13.267Z"}, {"lat": "44.141449", "lng": "9.671346", "elevation": "210.89999389648438", "time": "2013-09-20T09:09:14.305Z"}, {"lat": "44.141409", "lng": "9.671437", "elevation": "212.5", "time": "2013-09-20T09:09:19.330Z"}, {"lat": "44.141397", "lng": "9.67145", "elevation": "212.10000610351563", "time": "2013-09-20T09:09:20.267Z"}, {"lat": "44.141331", "lng": "9.671521", "elevation": "211.39999389648438", "time": "2013-09-20T09:09:27.267Z"}, {"lat": "44.141326", "lng": "9.671536", "elevation": "211.3000030517578", "time": "2013-09-20T09:09:28.285Z"}, {"lat": "44.141303", "lng": "9.671647", "elevation": "212.6999969482422", "time": "2013-09-20T09:09:34.347Z"}, {"lat": "44.141298", "lng": "9.671664", "elevation": "212.60000610351563", "time": "2013-09-20T09:09:35.362Z"}, {"lat": "44.141252", "lng": "9.671752", "elevation": "211.3000030517578", "time": "2013-09-20T09:09:41.277Z"}, {"lat": "44.141247", "lng": "9.671769", "elevation": "211.1999969482422", "time": "2013-09-20T09:09:42.325Z"}, {"lat": "44.141196", "lng": "9.671864", "elevation": "213.8000030517578", "time": "2013-09-20T09:09:48.287Z"}, {"lat": "44.141177", "lng": "9.671877", "elevation": "213.3000030517578", "time": "2013-09-20T09:09:49.287Z"}, {"lat": "44.141107", "lng": "9.671917", "elevation": "214.3000030517578", "time": "2013-09-20T09:09:53.318Z"}, {"lat": "44.141094", "lng": "9.671927", "elevation": "214.10000610351563", "time": "2013-09-20T09:09:54.286Z"}, {"lat": "44.141035", "lng": "9.672006", "elevation": "213.6999969482422", "time": "2013-09-20T09:10:00.393Z"}, {"lat": "44.141027", "lng": "9.672018", "elevation": "212.60000610351563", "time": "2013-09-20T09:10:01.294Z"}, {"lat": "44.14094", "lng": "9.672043", "elevation": "213.1999969482422", "time": "2013-09-20T09:10:07.286Z"}, {"lat": "44.140927", "lng": "9.672048", "elevation": "214.39999389648438", "time": "2013-09-20T09:10:08.301Z"}, {"lat": "44.140852", "lng": "9.672109", "elevation": "217.5", "time": "2013-09-20T09:10:15.367Z"}, {"lat": "44.140845", "lng": "9.672117", "elevation": "217.0", "time": "2013-09-20T09:10:16.345Z"}, {"lat": "44.140788", "lng": "9.672193", "elevation": "215.60000610351563", "time": "2013-09-20T09:10:28.273Z"}, {"lat": "44.140779", "lng": "9.672203", "elevation": "216.1999969482422", "time": "2013-09-20T09:10:29.281Z"}, {"lat": "44.140702", "lng": "9.672256", "elevation": "214.89999389648438", "time": "2013-09-20T09:10:45.297Z"}, {"lat": "44.140699", "lng": "9.672262", "elevation": "214.1999969482422", "time": "2013-09-20T09:10:46.331Z"}, {"lat": "44.140637", "lng": "9.672337", "elevation": "216.10000610351563", "time": "2013-09-20T09:10:57.306Z"}, {"lat": "44.140626", "lng": "9.672344", "elevation": "216.1999969482422", "time": "2013-09-20T09:10:58.274Z"}, {"lat": "44.140567", "lng": "9.67243", "elevation": "216.10000610351563", "time": "2013-09-20T09:11:05.308Z"}, {"lat": "44.140564", "lng": "9.672447", "elevation": "216.8000030517578", "time": "2013-09-20T09:11:06.283Z"}, {"lat": "44.140541", "lng": "9.672555", "elevation": "218.5", "time": "2013-09-20T09:11:12.293Z"}, {"lat": "44.140535", "lng": "9.672568", "elevation": "218.89999389648438", "time": "2013-09-20T09:11:13.309Z"}, {"lat": "44.14053", "lng": "9.672691", "elevation": "218.0", "time": "2013-09-20T09:11:23.294Z"}, {"lat": "44.140535", "lng": "9.672708", "elevation": "216.89999389648438", "time": "2013-09-20T09:11:24.308Z"}, {"lat": "44.140551", "lng": "9.672822", "elevation": "221.10000610351563", "time": "2013-09-20T09:11:36.304Z"}, {"lat": "44.140552", "lng": "9.672832", "elevation": "221.5", "time": "2013-09-20T09:11:37.287Z"}, {"lat": "44.140572", "lng": "9.672943", "elevation": "219.8000030517578", "time": "2013-09-20T09:11:47.311Z"}, {"lat": "44.140574", "lng": "9.672955", "elevation": "219.3000030517578", "time": "2013-09-20T09:11:48.303Z"}, {"lat": "44.140561", "lng": "9.673054", "elevation": "218.5", "time": "2013-09-20T09:12:00.309Z"}, {"lat": "44.140562", "lng": "9.673054", "elevation": "218.6999969482422", "time": "2013-09-20T09:12:01.281Z"}, {"lat": "44.140573", "lng": "9.673073", "elevation": "217.6999969482422", "time": "2013-09-20T09:12:42.300Z"}, {"lat": "44.140572", "lng": "9.673081", "elevation": "216.60000610351563", "time": "2013-09-20T09:12:43.380Z"}, {"lat": "44.140562", "lng": "9.673203", "elevation": "212.5", "time": "2013-09-20T09:12:50.300Z"}, {"lat": "44.140571", "lng": "9.673217", "elevation": "212.39999389648438", "time": "2013-09-20T09:12:51.357Z"}, {"lat": "44.140627", "lng": "9.673314", "elevation": "209.8000030517578", "time": "2013-09-20T09:12:59.363Z"}, {"lat": "44.140628", "lng": "9.673317", "elevation": "210.10000610351563", "time": "2013-09-20T09:13:00.451Z"}, {"lat": "44.140604", "lng": "9.673426", "elevation": "208.89999389648438", "time": "2013-09-20T09:13:09.349Z"}, {"lat": "44.140605", "lng": "9.673443", "elevation": "206.89999389648438", "time": "2013-09-20T09:13:10.332Z"}, {"lat": "44.140649", "lng": "9.67355", "elevation": "204.89999389648438", "time": "2013-09-20T09:13:18.320Z"}, {"lat": "44.140649", "lng": "9.673571", "elevation": "204.8000030517578", "time": "2013-09-20T09:13:19.320Z"}, {"lat": "44.140614", "lng": "9.673678", "elevation": "208.0", "time": "2013-09-20T09:13:24.313Z"}, {"lat": "44.140609", "lng": "9.673696", "elevation": "208.5", "time": "2013-09-20T09:13:25.307Z"}, {"lat": "44.140609", "lng": "9.673815", "elevation": "209.1999969482422", "time": "2013-09-20T09:13:33.316Z"}, {"lat": "44.140604", "lng": "9.673838", "elevation": "208.8000030517578", "time": "2013-09-20T09:13:34.347Z"}, {"lat": "44.140612", "lng": "9.673959", "elevation": "205.10000610351563", "time": "2013-09-20T09:13:41.294Z"}, {"lat": "44.140623", "lng": "9.673962", "elevation": "205.5", "time": "2013-09-20T09:13:42.294Z"}, {"lat": "44.140633", "lng": "9.67408", "elevation": "206.60000610351563", "time": "2013-09-20T09:13:56.327Z"}, {"lat": "44.140625", "lng": "9.674094", "elevation": "205.3000030517578", "time": "2013-09-20T09:13:57.367Z"}, {"lat": "44.14059", "lng": "9.674206", "elevation": "204.5", "time": "2013-09-20T09:14:04.403Z"}, {"lat": "44.140588", "lng": "9.674225", "elevation": "204.89999389648438", "time": "2013-09-20T09:14:05.377Z"}, {"lat": "44.140568", "lng": "9.674345", "elevation": "206.0", "time": "2013-09-20T09:14:19.314Z"}, {"lat": "44.140567", "lng": "9.674357", "elevation": "206.39999389648438", "time": "2013-09-20T09:14:20.324Z"}, {"lat": "44.140591", "lng": "9.674469", "elevation": "207.1999969482422", "time": "2013-09-20T09:14:28.305Z"}, {"lat": "44.140591", "lng": "9.674481", "elevation": "206.89999389648438", "time": "2013-09-20T09:14:29.331Z"}, {"lat": "44.140605", "lng": "9.674598", "elevation": "209.60000610351563", "time": "2013-09-20T09:14:41.301Z"}, {"lat": "44.140609", "lng": "9.674611", "elevation": "210.60000610351563", "time": "2013-09-20T09:14:42.300Z"}, {"lat": "44.140588", "lng": "9.674654", "elevation": "211.3000030517578", "time": "2013-09-20T09:14:52.377Z"}, {"lat": "44.140587", "lng": "9.674654", "elevation": "211.10000610351563", "time": "2013-09-20T09:14:53.377Z"}, {"lat": "44.140596", "lng": "9.674662", "elevation": "210.3000030517578", "time": "2013-09-20T09:15:08.326Z"}, {"lat": "44.140596", "lng": "9.674669", "elevation": "210.10000610351563", "time": "2013-09-20T09:15:09.303Z"}, {"lat": "44.140624", "lng": "9.674769", "elevation": "205.1999969482422", "time": "2013-09-20T09:15:15.295Z"}, {"lat": "44.140634", "lng": "9.67479", "elevation": "204.60000610351563", "time": "2013-09-20T09:15:16.295Z"}, {"lat": "44.140666", "lng": "9.67489", "elevation": "206.10000610351563", "time": "2013-09-20T09:15:21.336Z"}, {"lat": "44.140673", "lng": "9.67491", "elevation": "207.39999389648438", "time": "2013-09-20T09:15:22.319Z"}, {"lat": "44.140681", "lng": "9.67502", "elevation": "207.6999969482422", "time": "2013-09-20T09:15:26.308Z"}, {"lat": "44.140676", "lng": "9.675045", "elevation": "209.3000030517578", "time": "2013-09-20T09:15:27.294Z"}, {"lat": "44.140648", "lng": "9.675161", "elevation": "210.10000610351563", "time": "2013-09-20T09:15:33.304Z"}, {"lat": "44.140649", "lng": "9.675166", "elevation": "210.0", "time": "2013-09-20T09:15:34.317Z"}, {"lat": "44.140668", "lng": "9.675164", "elevation": "210.0", "time": "2013-09-20T09:15:41.295Z"}, {"lat": "44.140669", "lng": "9.675165", "elevation": "210.0", "time": "2013-09-20T09:15:42.312Z"}, {"lat": "44.140668", "lng": "9.675169", "elevation": "209.1999969482422", "time": "2013-09-20T09:16:01.315Z"}, {"lat": "44.140663", "lng": "9.675176", "elevation": "208.1999969482422", "time": "2013-09-20T09:16:02.333Z"}, {"lat": "44.140639", "lng": "9.675219", "elevation": "207.10000610351563", "time": "2013-09-20T09:16:06.354Z"}, {"lat": "44.140631", "lng": "9.675516", "elevation": "195.5", "time": "2013-09-20T09:16:40.254Z"}, {"lat": "44.1406", "lng": "9.675602", "elevation": "206.89999389648438", "time": "2013-09-20T09:16:44.253Z"}, {"lat": "44.140593", "lng": "9.675632", "elevation": "209.0", "time": "2013-09-20T09:16:45.231Z"}, {"lat": "44.140526", "lng": "9.675678", "elevation": "207.89999389648438", "time": "2013-09-20T09:16:50.222Z"}, {"lat": "44.140505", "lng": "9.675667", "elevation": "207.3000030517578", "time": "2013-09-20T09:16:51.262Z"}, {"lat": "44.140521", "lng": "9.675644", "elevation": "205.60000610351563", "time": "2013-09-20T09:16:59.234Z"}, {"lat": "44.140522", "lng": "9.675644", "elevation": "205.6999969482422", "time": "2013-09-20T09:17:00.270Z"}, {"lat": "44.140515", "lng": "9.675657", "elevation": "206.0", "time": "2013-09-20T09:17:55.237Z"}, {"lat": "44.140517", "lng": "9.675663", "elevation": "207.5", "time": "2013-09-20T09:17:56.239Z"}, {"lat": "44.14057", "lng": "9.675754", "elevation": "209.39999389648438", "time": "2013-09-20T09:18:03.245Z"}, {"lat": "44.14058", "lng": "9.675765", "elevation": "209.1999969482422", "time": "2013-09-20T09:18:04.238Z"}, {"lat": "44.140586", "lng": "9.675823", "elevation": "211.5", "time": "2013-09-20T09:18:16.245Z"}, {"lat": "44.140586", "lng": "9.675825", "elevation": "211.60000610351563", "time": "2013-09-20T09:18:17.255Z"}, {"lat": "44.140592", "lng": "9.675829", "elevation": "211.6999969482422", "time": "2013-09-20T09:18:27.265Z"}, {"lat": "44.140593", "lng": "9.675839", "elevation": "212.6999969482422", "time": "2013-09-20T09:18:28.239Z"}, {"lat": "44.140558", "lng": "9.675943", "elevation": "219.39999389648438", "time": "2013-09-20T09:18:35.254Z"}, {"lat": "44.140548", "lng": "9.675955", "elevation": "220.1999969482422", "time": "2013-09-20T09:18:36.272Z"}, {"lat": "44.140505", "lng": "9.676063", "elevation": "222.6999969482422", "time": "2013-09-20T09:18:41.262Z"}, {"lat": "44.140501", "lng": "9.676086", "elevation": "223.3000030517578", "time": "2013-09-20T09:18:42.242Z"}, {"lat": "44.140424", "lng": "9.676136", "elevation": "223.60000610351563", "time": "2013-09-20T09:18:48.329Z"}, {"lat": "44.140408", "lng": "9.676142", "elevation": "223.60000610351563", "time": "2013-09-20T09:18:49.258Z"}, {"lat": "44.14036", "lng": "9.676245", "elevation": "221.0", "time": "2013-09-20T09:18:57.256Z"}, {"lat": "44.140359", "lng": "9.67626", "elevation": "219.8000030517578", "time": "2013-09-20T09:18:58.264Z"}, {"lat": "44.140321", "lng": "9.676372", "elevation": "220.60000610351563", "time": "2013-09-20T09:19:08.242Z"}, {"lat": "44.140317", "lng": "9.676377", "elevation": "221.0", "time": "2013-09-20T09:19:09.241Z"}, {"lat": "44.140239", "lng": "9.676438", "elevation": "218.89999389648438", "time": "2013-09-20T09:19:25.242Z"}, {"lat": "44.140236", "lng": "9.676448", "elevation": "220.5", "time": "2013-09-20T09:19:26.252Z"}, {"lat": "44.140213", "lng": "9.676558", "elevation": "213.5", "time": "2013-09-20T09:19:36.244Z"}, {"lat": "44.140218", "lng": "9.67658", "elevation": "212.3000030517578", "time": "2013-09-20T09:19:37.252Z"}, {"lat": "44.140208", "lng": "9.676694", "elevation": "208.10000610351563", "time": "2013-09-20T09:19:44.317Z"}, {"lat": "44.140202", "lng": "9.676706", "elevation": "207.1999969482422", "time": "2013-09-20T09:19:45.245Z"}, {"lat": "44.140178", "lng": "9.67682", "elevation": "206.60000610351563", "time": "2013-09-20T09:19:53.350Z"}, {"lat": "44.140177", "lng": "9.676834", "elevation": "207.3000030517578", "time": "2013-09-20T09:19:54.269Z"}, {"lat": "44.140178", "lng": "9.676951", "elevation": "204.5", "time": "2013-09-20T09:20:07.247Z"}, {"lat": "44.140184", "lng": "9.676964", "elevation": "204.10000610351563", "time": "2013-09-20T09:20:08.249Z"}, {"lat": "44.140158", "lng": "9.677077", "elevation": "206.10000610351563", "time": "2013-09-20T09:20:17.254Z"}, {"lat": "44.140146", "lng": "9.677089", "elevation": "206.60000610351563", "time": "2013-09-20T09:20:18.257Z"}, {"lat": "44.140076", "lng": "9.677164", "elevation": "208.10000610351563", "time": "2013-09-20T09:20:24.263Z"}, {"lat": "44.140066", "lng": "9.677187", "elevation": "207.3000030517578", "time": "2013-09-20T09:20:25.240Z"}, {"lat": "44.140011", "lng": "9.677273", "elevation": "208.39999389648438", "time": "2013-09-20T09:20:31.239Z"}, {"lat": "44.140003", "lng": "9.677287", "elevation": "208.3000030517578", "time": "2013-09-20T09:20:32.354Z"}, {"lat": "44.139937", "lng": "9.677346", "elevation": "209.39999389648438", "time": "2013-09-20T09:20:38.400Z"}, {"lat": "44.139926", "lng": "9.677353", "elevation": "210.0", "time": "2013-09-20T09:20:39.352Z"}, {"lat": "44.139849", "lng": "9.677395", "elevation": "208.39999389648438", "time": "2013-09-20T09:20:46.251Z"}, {"lat": "44.139841", "lng": "9.677402", "elevation": "210.39999389648438", "time": "2013-09-20T09:20:47.272Z"}, {"lat": "44.13977", "lng": "9.677457", "elevation": "211.60000610351563", "time": "2013-09-20T09:20:54.275Z"}, {"lat": "44.139763", "lng": "9.677472", "elevation": "212.0", "time": "2013-09-20T09:20:55.243Z"}, {"lat": "44.139711", "lng": "9.677569", "elevation": "214.0", "time": "2013-09-20T09:21:04.245Z"}, {"lat": "44.139705", "lng": "9.677577", "elevation": "213.60000610351563", "time": "2013-09-20T09:21:05.251Z"}, {"lat": "44.139645", "lng": "9.677534", "elevation": "217.1999969482422", "time": "2013-09-20T09:21:20.247Z"}, {"lat": "44.139644", "lng": "9.677533", "elevation": "217.1999969482422", "time": "2013-09-20T09:21:21.252Z"}, {"lat": "44.139635", "lng": "9.677543", "elevation": "216.89999389648438", "time": "2013-09-20T09:21:30.277Z"}, {"lat": "44.139631", "lng": "9.677547", "elevation": "217.10000610351563", "time": "2013-09-20T09:21:31.253Z"}, {"lat": "44.139551", "lng": "9.677589", "elevation": "218.8000030517578", "time": "2013-09-20T09:21:35.259Z"}, {"lat": "44.139524", "lng": "9.67759", "elevation": "218.60000610351563", "time": "2013-09-20T09:21:36.248Z"}, {"lat": "44.139454", "lng": "9.677585", "elevation": "219.10000610351563", "time": "2013-09-20T09:21:39.283Z"}, {"lat": "44.139433", "lng": "9.677585", "elevation": "218.89999389648438", "time": "2013-09-20T09:21:40.253Z"}, {"lat": "44.13935", "lng": "9.677614", "elevation": "219.1999969482422", "time": "2013-09-20T09:21:44.252Z"}, {"lat": "44.139334", "lng": "9.677625", "elevation": "218.60000610351563", "time": "2013-09-20T09:21:45.262Z"}, {"lat": "44.139269", "lng": "9.677702", "elevation": "216.5", "time": "2013-09-20T09:21:49.284Z"}, {"lat": "44.139256", "lng": "9.677719", "elevation": "214.89999389648438", "time": "2013-09-20T09:21:50.277Z"}, {"lat": "44.13917", "lng": "9.677756", "elevation": "220.89999389648438", "time": "2013-09-20T09:21:57.255Z"}, {"lat": "44.139157", "lng": "9.677764", "elevation": "221.5", "time": "2013-09-20T09:21:58.270Z"}, {"lat": "44.13907", "lng": "9.677779", "elevation": "221.5", "time": "2013-09-20T09:22:06.319Z"}, {"lat": "44.139058", "lng": "9.677776", "elevation": "220.6999969482422", "time": "2013-09-20T09:22:07.350Z"}, {"lat": "44.139001", "lng": "9.677871", "elevation": "224.0", "time": "2013-09-20T09:22:15.265Z"}, {"lat": "44.138985", "lng": "9.677885", "elevation": "225.0", "time": "2013-09-20T09:22:16.321Z"}, {"lat": "44.138915", "lng": "9.677936", "elevation": "227.10000610351563", "time": "2013-09-20T09:22:20.255Z"}, {"lat": "44.138896", "lng": "9.677943", "elevation": "227.39999389648438", "time": "2013-09-20T09:22:21.280Z"}, {"lat": "44.138807", "lng": "9.677963", "elevation": "228.60000610351563", "time": "2013-09-20T09:22:27.258Z"}, {"lat": "44.138795", "lng": "9.677966", "elevation": "228.5", "time": "2013-09-20T09:22:28.288Z"}, {"lat": "44.13872", "lng": "9.677989", "elevation": "229.60000610351563", "time": "2013-09-20T09:22:33.282Z"}, {"lat": "44.138702", "lng": "9.677992", "elevation": "232.39999389648438", "time": "2013-09-20T09:22:34.279Z"}, {"lat": "44.138622", "lng": "9.677985", "elevation": "231.39999389648438", "time": "2013-09-20T09:22:38.282Z"}, {"lat": "44.138604", "lng": "9.677982", "elevation": "232.10000610351563", "time": "2013-09-20T09:22:39.282Z"}, {"lat": "44.138516", "lng": "9.677967", "elevation": "234.60000610351563", "time": "2013-09-20T09:22:45.267Z"}, {"lat": "44.138508", "lng": "9.677969", "elevation": "236.3000030517578", "time": "2013-09-20T09:22:46.285Z"}, {"lat": "44.138439", "lng": "9.678037", "elevation": "238.89999389648438", "time": "2013-09-20T09:22:54.343Z"}, {"lat": "44.138428", "lng": "9.678039", "elevation": "240.1999969482422", "time": "2013-09-20T09:22:55.326Z"}, {"lat": "44.138345", "lng": "9.678053", "elevation": "235.39999389648438", "time": "2013-09-20T09:23:07.297Z"}, {"lat": "44.138338", "lng": "9.678057", "elevation": "236.39999389648438", "time": "2013-09-20T09:23:08.282Z"}, {"lat": "44.138254", "lng": "9.678067", "elevation": "240.89999389648438", "time": "2013-09-20T09:23:17.285Z"}, {"lat": "44.138247", "lng": "9.678071", "elevation": "240.8000030517578", "time": "2013-09-20T09:23:18.359Z"}, {"lat": "44.138243", "lng": "9.678189", "elevation": "224.6999969482422", "time": "2013-09-20T09:23:38.272Z"}, {"lat": "44.138243", "lng": "9.678197", "elevation": "224.5", "time": "2013-09-20T09:23:39.280Z"}, {"lat": "44.138248", "lng": "9.678206", "elevation": "223.8000030517578", "time": "2013-09-20T09:23:43.366Z"}, {"lat": "44.138248", "lng": "9.678205", "elevation": "224.8000030517578", "time": "2013-09-20T09:23:44.326Z"}, {"lat": "44.13825", "lng": "9.678205", "elevation": "223.10000610351563", "time": "2013-09-20T09:23:46.278Z"}, {"lat": "44.138254", "lng": "9.678206", "elevation": "222.89999389648438", "time": "2013-09-20T09:23:47.294Z"}, {"lat": "44.138273", "lng": "9.678225", "elevation": "219.39999389648438", "time": "2013-09-20T09:23:55.289Z"}, {"lat": "44.138273", "lng": "9.678226", "elevation": "219.3000030517578", "time": "2013-09-20T09:23:56.295Z"}, {"lat": "44.138272", "lng": "9.678229", "elevation": "219.0", "time": "2013-09-20T09:23:59.366Z"}, {"lat": "44.138272", "lng": "9.678235", "elevation": "216.6999969482422", "time": "2013-09-20T09:24:00.358Z"}, {"lat": "44.13827", "lng": "9.678347", "elevation": "205.6999969482422", "time": "2013-09-20T09:24:06.311Z"}, {"lat": "44.138268", "lng": "9.678371", "elevation": "204.8000030517578", "time": "2013-09-20T09:24:07.289Z"}, {"lat": "44.138286", "lng": "9.678438", "elevation": "204.8000030517578", "time": "2013-09-20T09:24:17.283Z"}, {"lat": "44.138286", "lng": "9.678439", "elevation": "204.5", "time": "2013-09-20T09:24:18.321Z"}, {"lat": "44.138282", "lng": "9.678456", "elevation": "202.89999389648438", "time": "2013-09-20T09:24:32.284Z"}, {"lat": "44.13828", "lng": "9.678465", "elevation": "202.3000030517578", "time": "2013-09-20T09:24:33.275Z"}, {"lat": "44.138262", "lng": "9.678573", "elevation": "197.1999969482422", "time": "2013-09-20T09:24:39.282Z"}, {"lat": "44.138254", "lng": "9.678589", "elevation": "197.6999969482422", "time": "2013-09-20T09:24:40.350Z"}, {"lat": "44.1382", "lng": "9.678683", "elevation": "196.39999389648438", "time": "2013-09-20T09:24:52.299Z"}, {"lat": "44.138196", "lng": "9.678692", "elevation": "195.0", "time": "2013-09-20T09:24:53.310Z"}, {"lat": "44.138166", "lng": "9.678792", "elevation": "196.10000610351563", "time": "2013-09-20T09:25:00.368Z"}, {"lat": "44.138159", "lng": "9.678807", "elevation": "196.3000030517578", "time": "2013-09-20T09:25:01.268Z"}, {"lat": "44.138194", "lng": "9.678917", "elevation": "198.6999969482422", "time": "2013-09-20T09:25:12.278Z"}, {"lat": "44.138197", "lng": "9.678928", "elevation": "198.8000030517578", "time": "2013-09-20T09:25:13.270Z"}, {"lat": "44.138226", "lng": "9.678961", "elevation": "197.39999389648438", "time": "2013-09-20T09:25:22.286Z"}, {"lat": "44.138225", "lng": "9.678964", "elevation": "197.1999969482422", "time": "2013-09-20T09:25:23.295Z"}, {"lat": "44.13823", "lng": "9.678985", "elevation": "194.39999389648438", "time": "2013-09-20T09:25:41.296Z"}, {"lat": "44.138232", "lng": "9.678992", "elevation": "194.6999969482422", "time": "2013-09-20T09:25:42.279Z"}, {"lat": "44.138286", "lng": "9.679026", "elevation": "190.8000030517578", "time": "2013-09-20T09:25:53.328Z"}, {"lat": "44.138286", "lng": "9.679026", "elevation": "190.5", "time": "2013-09-20T09:25:54.291Z"}, {"lat": "44.138286", "lng": "9.679034", "elevation": "191.0", "time": "2013-09-20T09:25:58.330Z"}, {"lat": "44.138288", "lng": "9.679045", "elevation": "190.1999969482422", "time": "2013-09-20T09:25:59.291Z"}, {"lat": "44.138312", "lng": "9.679158", "elevation": "185.89999389648438", "time": "2013-09-20T09:26:07.275Z"}, {"lat": "44.138313", "lng": "9.679171", "elevation": "184.6999969482422", "time": "2013-09-20T09:26:08.298Z"}, {"lat": "44.138306", "lng": "9.679292", "elevation": "183.10000610351563", "time": "2013-09-20T09:26:21.294Z"}, {"lat": "44.138303", "lng": "9.679298", "elevation": "183.39999389648438", "time": "2013-09-20T09:26:22.282Z"}, {"lat": "44.138285", "lng": "9.679396", "elevation": "176.60000610351563", "time": "2013-09-20T09:26:40.299Z"}, {"lat": "44.138285", "lng": "9.679395", "elevation": "176.6999969482422", "time": "2013-09-20T09:26:41.292Z"}, {"lat": "44.138283", "lng": "9.679398", "elevation": "176.60000610351563", "time": "2013-09-20T09:26:43.291Z"}, {"lat": "44.138279", "lng": "9.679403", "elevation": "176.3000030517578", "time": "2013-09-20T09:26:44.301Z"}, {"lat": "44.138229", "lng": "9.679493", "elevation": "172.5", "time": "2013-09-20T09:26:55.358Z"}, {"lat": "44.138228", "lng": "9.679506", "elevation": "172.89999389648438", "time": "2013-09-20T09:26:56.326Z"}, {"lat": "44.138213", "lng": "9.679581", "elevation": "172.60000610351563", "time": "2013-09-20T09:27:06.325Z"}, {"lat": "44.138215", "lng": "9.679582", "elevation": "172.6999969482422", "time": "2013-09-20T09:27:07.294Z"}, {"lat": "44.138199", "lng": "9.679572", "elevation": "172.0", "time": "2013-09-20T09:27:23.288Z"}, {"lat": "44.138195", "lng": "9.679574", "elevation": "172.1999969482422", "time": "2013-09-20T09:27:24.287Z"}, {"lat": "44.138114", "lng": "9.679621", "elevation": "169.5", "time": "2013-09-20T09:27:32.315Z"}, {"lat": "44.138106", "lng": "9.679629", "elevation": "170.60000610351563", "time": "2013-09-20T09:27:33.290Z"}, {"lat": "44.138108", "lng": "9.67968", "elevation": "168.1999969482422", "time": "2013-09-20T09:27:41.305Z"}, {"lat": "44.138107", "lng": "9.679679", "elevation": "168.1999969482422", "time": "2013-09-20T09:27:42.305Z"}, {"lat": "44.138102", "lng": "9.679695", "elevation": "165.39999389648438", "time": "2013-09-20T09:27:54.314Z"}, {"lat": "44.138099", "lng": "9.6797", "elevation": "165.5", "time": "2013-09-20T09:27:55.296Z"}, {"lat": "44.138052", "lng": "9.679789", "elevation": "166.0", "time": "2013-09-20T09:28:04.304Z"}, {"lat": "44.138043", "lng": "9.679801", "elevation": "166.60000610351563", "time": "2013-09-20T09:28:05.322Z"}, {"lat": "44.137982", "lng": "9.679877", "elevation": "163.5", "time": "2013-09-20T09:28:14.289Z"}, {"lat": "44.137973", "lng": "9.679881", "elevation": "163.6999969482422", "time": "2013-09-20T09:28:15.376Z"}, {"lat": "44.137898", "lng": "9.679945", "elevation": "163.1999969482422", "time": "2013-09-20T09:28:22.307Z"}, {"lat": "44.137892", "lng": "9.679957", "elevation": "163.10000610351563", "time": "2013-09-20T09:28:23.299Z"}, {"lat": "44.137811", "lng": "9.680002", "elevation": "161.0", "time": "2013-09-20T09:28:33.301Z"}, {"lat": "44.137806", "lng": "9.680006", "elevation": "161.6999969482422", "time": "2013-09-20T09:28:34.301Z"}, {"lat": "44.137785", "lng": "9.680024", "elevation": "160.6999969482422", "time": "2013-09-20T09:28:40.318Z"}, {"lat": "44.137789", "lng": "9.680023", "elevation": "161.10000610351563", "time": "2013-09-20T09:28:41.318Z"}, {"lat": "44.137792", "lng": "9.680034", "elevation": "162.5", "time": "2013-09-20T09:28:49.325Z"}, {"lat": "44.137787", "lng": "9.680036", "elevation": "162.1999969482422", "time": "2013-09-20T09:28:50.318Z"}, {"lat": "44.137728", "lng": "9.680109", "elevation": "156.8000030517578", "time": "2013-09-20T09:28:58.302Z"}, {"lat": "44.137718", "lng": "9.680118", "elevation": "155.6999969482422", "time": "2013-09-20T09:28:59.309Z"}, {"lat": "44.13766", "lng": "9.680206", "elevation": "153.60000610351563", "time": "2013-09-20T09:29:07.310Z"}, {"lat": "44.137658", "lng": "9.680217", "elevation": "152.39999389648438", "time": "2013-09-20T09:29:08.311Z"}, {"lat": "44.137629", "lng": "9.68033", "elevation": "151.39999389648438", "time": "2013-09-20T09:29:25.294Z"}, {"lat": "44.137629", "lng": "9.680338", "elevation": "151.1999969482422", "time": "2013-09-20T09:29:26.322Z"}, {"lat": "44.137663", "lng": "9.680357", "elevation": "148.1999969482422", "time": "2013-09-20T09:29:35.304Z"}, {"lat": "44.137662", "lng": "9.680357", "elevation": "148.1999969482422", "time": "2013-09-20T09:29:36.298Z"}, {"lat": "44.137657", "lng": "9.680357", "elevation": "147.8000030517578", "time": "2013-09-20T09:29:38.260Z"}, {"lat": "44.137652", "lng": "9.680356", "elevation": "147.89999389648438", "time": "2013-09-20T09:29:38.294Z"}, {"lat": "44.137566", "lng": "9.680328", "elevation": "147.89999389648438", "time": "2013-09-20T09:29:49.322Z"}, {"lat": "44.137562", "lng": "9.680335", "elevation": "148.3000030517578", "time": "2013-09-20T09:29:50.307Z"}, {"lat": "44.137504", "lng": "9.680421", "elevation": "146.0", "time": "2013-09-20T09:30:01.319Z"}, {"lat": "44.137495", "lng": "9.680429", "elevation": "146.8000030517578", "time": "2013-09-20T09:30:02.322Z"}, {"lat": "44.137471", "lng": "9.68045", "elevation": "142.1999969482422", "time": "2013-09-20T09:30:08.322Z"}, {"lat": "44.137475", "lng": "9.680451", "elevation": "142.39999389648438", "time": "2013-09-20T09:30:09.305Z"}, {"lat": "44.13748", "lng": "9.68045", "elevation": "142.60000610351563", "time": "2013-09-20T09:30:10.322Z"}, {"lat": "44.137481", "lng": "9.68045", "elevation": "142.60000610351563", "time": "2013-09-20T09:30:11.308Z"}, {"lat": "44.137477", "lng": "9.680446", "elevation": "142.8000030517578", "time": "2013-09-20T09:30:13.300Z"}, {"lat": "44.137471", "lng": "9.680443", "elevation": "145.0", "time": "2013-09-20T09:30:14.308Z"}, {"lat": "44.137448", "lng": "9.680447", "elevation": "144.60000610351563", "time": "2013-09-20T09:30:35.325Z"}, {"lat": "44.137448", "lng": "9.680446", "elevation": "144.5", "time": "2013-09-20T09:30:36.319Z"}, {"lat": "44.137441", "lng": "9.680445", "elevation": "144.10000610351563", "time": "2013-09-20T09:30:41.373Z"}, {"lat": "44.137436", "lng": "9.680444", "elevation": "143.6999969482422", "time": "2013-09-20T09:30:42.333Z"}, {"lat": "44.137362", "lng": "9.680377", "elevation": "140.89999389648438", "time": "2013-09-20T09:30:58.336Z"}, {"lat": "44.137354", "lng": "9.680371", "elevation": "141.89999389648438", "time": "2013-09-20T09:30:59.326Z"}, {"lat": "44.137318", "lng": "9.680375", "elevation": "141.3000030517578", "time": "2013-09-20T09:31:07.407Z"}, {"lat": "44.137319", "lng": "9.680376", "elevation": "141.1999969482422", "time": "2013-09-20T09:31:08.446Z"}, {"lat": "44.137316", "lng": "9.680386", "elevation": "140.6999969482422", "time": "2013-09-20T09:31:12.376Z"}, {"lat": "44.137313", "lng": "9.680391", "elevation": "140.1999969482422", "time": "2013-09-20T09:31:13.304Z"}, {"lat": "44.137241", "lng": "9.680448", "elevation": "140.5", "time": "2013-09-20T09:31:22.335Z"}, {"lat": "44.137234", "lng": "9.680452", "elevation": "140.10000610351563", "time": "2013-09-20T09:31:23.426Z"}, {"lat": "44.137146", "lng": "9.680462", "elevation": "139.60000610351563", "time": "2013-09-20T09:31:38.435Z"}, {"lat": "44.137138", "lng": "9.680468", "elevation": "137.39999389648438", "time": "2013-09-20T09:31:39.355Z"}, {"lat": "44.137067", "lng": "9.680541", "elevation": "134.8000030517578", "time": "2013-09-20T09:31:48.350Z"}, {"lat": "44.137056", "lng": "9.680546", "elevation": "135.1999969482422", "time": "2013-09-20T09:31:48.378Z"}, {"lat": "44.136989", "lng": "9.680622", "elevation": "132.10000610351563", "time": "2013-09-20T09:31:58.072Z"}, {"lat": "44.136983", "lng": "9.680626", "elevation": "131.8000030517578", "time": "2013-09-20T09:31:58.411Z"}, {"lat": "44.13691", "lng": "9.680685", "elevation": "122.5", "time": "2013-09-20T09:32:14.311Z"}, {"lat": "44.1369", "lng": "9.680693", "elevation": "122.0999984741211", "time": "2013-09-20T09:32:15.324Z"}, {"lat": "44.136825", "lng": "9.680753", "elevation": "122.30000305175781", "time": "2013-09-20T09:32:24.311Z"}, {"lat": "44.13682", "lng": "9.680757", "elevation": "122.4000015258789", "time": "2013-09-20T09:32:25.318Z"}, {"lat": "44.13679", "lng": "9.680869", "elevation": "118.9000015258789", "time": "2013-09-20T09:32:35.310Z"}, {"lat": "44.136793", "lng": "9.680883", "elevation": "117.69999694824219", "time": "2013-09-20T09:32:36.325Z"}, {"lat": "44.136808", "lng": "9.680865", "elevation": "119.30000305175781", "time": "2013-09-20T09:32:43.487Z"}, {"lat": "44.136807", "lng": "9.680862", "elevation": "119.4000015258789", "time": "2013-09-20T09:32:44.399Z"}, {"lat": "44.136809", "lng": "9.680865", "elevation": "118.0", "time": "2013-09-20T09:32:46.322Z"}, {"lat": "44.136816", "lng": "9.680872", "elevation": "116.0", "time": "2013-09-20T09:32:47.375Z"}, {"lat": "44.136808", "lng": "9.680989", "elevation": "115.19999694824219", "time": "2013-09-20T09:33:01.335Z"}, {"lat": "44.136796", "lng": "9.680997", "elevation": "115.80000305175781", "time": "2013-09-20T09:33:02.329Z"}, {"lat": "44.136744", "lng": "9.681017", "elevation": "122.0", "time": "2013-09-20T09:33:15.387Z"}, {"lat": "44.136743", "lng": "9.681018", "elevation": "122.0", "time": "2013-09-20T09:33:16.440Z"}, {"lat": "44.136747", "lng": "9.681026", "elevation": "122.0", "time": "2013-09-20T09:33:34.434Z"}, {"lat": "44.136746", "lng": "9.681032", "elevation": "121.69999694824219", "time": "2013-09-20T09:33:35.447Z"}, {"lat": "44.136743", "lng": "9.681041", "elevation": "121.80000305175781", "time": "2013-09-20T09:33:38.809Z"}, {"lat": "44.136743", "lng": "9.681042", "elevation": "121.5999984741211", "time": "2013-09-20T09:33:39.348Z"}, {"lat": "44.136738", "lng": "9.681053", "elevation": "121.0999984741211", "time": "2013-09-20T09:33:55.372Z"}, {"lat": "44.136735", "lng": "9.68106", "elevation": "120.5", "time": "2013-09-20T09:33:56.339Z"}, {"lat": "44.13669", "lng": "9.681147", "elevation": "117.0", "time": "2013-09-20T09:34:09.499Z"}, {"lat": "44.136683", "lng": "9.681162", "elevation": "117.0", "time": "2013-09-20T09:34:10.421Z"}, {"lat": "44.136632", "lng": "9.681262", "elevation": "109.9000015258789", "time": "2013-09-20T09:34:18.314Z"}, {"lat": "44.13663", "lng": "9.681274", "elevation": "110.19999694824219", "time": "2013-09-20T09:34:18.356Z"}, {"lat": "44.136596", "lng": "9.681383", "elevation": "107.5", "time": "2013-09-20T09:34:43.441Z"}, {"lat": "44.136597", "lng": "9.681385", "elevation": "106.80000305175781", "time": "2013-09-20T09:34:43.473Z"}, {"lat": "44.136606", "lng": "9.681394", "elevation": "104.80000305175781", "time": "2013-09-20T09:34:48.412Z"}, {"lat": "44.136609", "lng": "9.681397", "elevation": "102.30000305175781", "time": "2013-09-20T09:34:48.444Z"}, {"lat": "44.13664", "lng": "9.681501", "elevation": "102.80000305175781", "time": "2013-09-20T09:35:01.438Z"}, {"lat": "44.13664", "lng": "9.6815", "elevation": "102.9000015258789", "time": "2013-09-20T09:35:02.371Z"}, {"lat": "44.13665", "lng": "9.681504", "elevation": "103.0", "time": "2013-09-20T09:35:31.443Z"}, {"lat": "44.13665", "lng": "9.681513", "elevation": "101.4000015258789", "time": "2013-09-20T09:35:32.341Z"}, {"lat": "44.13667", "lng": "9.681625", "elevation": "97.5", "time": "2013-09-20T09:35:38.483Z"}, {"lat": "44.136679", "lng": "9.681646", "elevation": "97.30000305175781", "time": "2013-09-20T09:35:39.341Z"}, {"lat": "44.13673", "lng": "9.681748", "elevation": "92.80000305175781", "time": "2013-09-20T09:35:50.359Z"}, {"lat": "44.136739", "lng": "9.681759", "elevation": "92.5999984741211", "time": "2013-09-20T09:35:51.437Z"}, {"lat": "44.136706", "lng": "9.681826", "elevation": "94.80000305175781", "time": "2013-09-20T09:36:08.146Z"}, {"lat": "44.136707", "lng": "9.681825", "elevation": "94.5", "time": "2013-09-20T09:36:08.390Z"}, {"lat": "44.136707", "lng": "9.681837", "elevation": "94.5", "time": "2013-09-20T09:36:39.352Z"}, {"lat": "44.136704", "lng": "9.681846", "elevation": "94.19999694824219", "time": "2013-09-20T09:36:40.378Z"}, {"lat": "44.136751", "lng": "9.68195", "elevation": "92.9000015258789", "time": "2013-09-20T09:36:48.422Z"}, {"lat": "44.136759", "lng": "9.681955", "elevation": "92.80000305175781", "time": "2013-09-20T09:36:49.442Z"}, {"lat": "44.136748", "lng": "9.682016", "elevation": "91.69999694824219", "time": "2013-09-20T09:37:00.429Z"}, {"lat": "44.136748", "lng": "9.682016", "elevation": "91.80000305175781", "time": "2013-09-20T09:37:01.458Z"}, {"lat": "44.136742", "lng": "9.682022", "elevation": "90.19999694824219", "time": "2013-09-20T09:37:20.330Z"}, {"lat": "44.136735", "lng": "9.68226", "elevation": "91.80000305175781", "time": "2013-09-20T09:37:38.350Z"}, {"lat": "44.136665", "lng": "9.682325", "elevation": "95.69999694824219", "time": "2013-09-20T09:37:52.361Z"}, {"lat": "44.136658", "lng": "9.682328", "elevation": "96.5", "time": "2013-09-20T09:37:53.354Z"}, {"lat": "44.136652", "lng": "9.682356", "elevation": "96.80000305175781", "time": "2013-09-20T09:38:01.402Z"}, {"lat": "44.136653", "lng": "9.682355", "elevation": "96.5", "time": "2013-09-20T09:38:02.353Z"}, {"lat": "44.136645", "lng": "9.682335", "elevation": "96.80000305175781", "time": "2013-09-20T09:38:21.350Z"}, {"lat": "44.136642", "lng": "9.682327", "elevation": "96.9000015258789", "time": "2013-09-20T09:38:22.352Z"}, {"lat": "44.136583", "lng": "9.682238", "elevation": "96.9000015258789", "time": "2013-09-20T09:38:29.385Z"}, {"lat": "44.136569", "lng": "9.682232", "elevation": "97.4000015258789", "time": "2013-09-20T09:38:30.362Z"}, {"lat": "44.136498", "lng": "9.682229", "elevation": "98.5", "time": "2013-09-20T09:38:34.355Z"}, {"lat": "44.136478", "lng": "9.68223", "elevation": "98.5999984741211", "time": "2013-09-20T09:38:35.346Z"}, {"lat": "44.136424", "lng": "9.682296", "elevation": "96.19999694824219", "time": "2013-09-20T09:38:50.350Z"}, {"lat": "44.136424", "lng": "9.682297", "elevation": "96.0999984741211", "time": "2013-09-20T09:38:51.347Z"}, {"lat": "44.136423", "lng": "9.682303", "elevation": "97.5999984741211", "time": "2013-09-20T09:40:53.088Z"}, {"lat": "44.136423", "lng": "9.682312", "elevation": "98.19999694824219", "time": "2013-09-20T09:40:53.412Z"}, {"lat": "44.1364", "lng": "9.682417", "elevation": "94.5", "time": "2013-09-20T09:40:58.346Z"}, {"lat": "44.136392", "lng": "9.682442", "elevation": "93.69999694824219", "time": "2013-09-20T09:40:59.357Z"}, {"lat": "44.136363", "lng": "9.682493", "elevation": "92.9000015258789", "time": "2013-09-20T09:41:02.357Z"}, {"lat": "44.136197", "lng": "9.682553", "elevation": "95.30000305175781", "time": "2013-09-20T09:41:56.360Z"}, {"lat": "44.136195", "lng": "9.682557", "elevation": "95.19999694824219", "time": "2013-09-20T09:41:57.381Z"}, {"lat": "44.136195", "lng": "9.682557", "elevation": "95.19999694824219", "time": "2013-09-20T09:41:58.201Z"}, {"lat": "44.136191", "lng": "9.682562", "elevation": "95.0999984741211", "time": "2013-09-20T09:41:58.415Z"}, {"lat": "44.136141", "lng": "9.682635", "elevation": "95.5", "time": "2013-09-20T09:42:01.418Z"}, {"lat": "44.136117", "lng": "9.68266", "elevation": "95.30000305175781", "time": "2013-09-20T09:42:02.411Z"}, {"lat": "44.136062", "lng": "9.682709", "elevation": "95.30000305175781", "time": "2013-09-20T09:42:04.388Z"}, {"lat": "44.136034", "lng": "9.682733", "elevation": "94.30000305175781", "time": "2013-09-20T09:42:05.350Z"}, {"lat": "44.135954", "lng": "9.682785", "elevation": "94.30000305175781", "time": "2013-09-20T09:42:08.350Z"}, {"lat": "44.135928", "lng": "9.682794", "elevation": "94.19999694824219", "time": "2013-09-20T09:42:09.434Z"}, {"lat": "44.135858", "lng": "9.682798", "elevation": "95.80000305175781", "time": "2013-09-20T09:42:17.378Z"}, {"lat": "44.135863", "lng": "9.682797", "elevation": "95.5999984741211", "time": "2013-09-20T09:42:18.394Z"}, {"lat": "44.135866", "lng": "9.682803", "elevation": "95.19999694824219", "time": "2013-09-20T09:42:27.370Z"}, {"lat": "44.135862", "lng": "9.682808", "elevation": "93.5999984741211", "time": "2013-09-20T09:42:28.402Z"}, {"lat": "44.135818", "lng": "9.682786", "elevation": "88.5999984741211", "time": "2013-09-20T09:42:38.527Z"}, {"lat": "44.135817", "lng": "9.682786", "elevation": "88.5999984741211", "time": "2013-09-20T09:42:39.437Z"}, {"lat": "44.135806", "lng": "9.682802", "elevation": "87.69999694824219", "time": "2013-09-20T09:42:49.407Z"}, {"lat": "44.1358", "lng": "9.682803", "elevation": "87.19999694824219", "time": "2013-09-20T09:42:50.384Z"}, {"lat": "44.135722", "lng": "9.682807", "elevation": "87.69999694824219", "time": "2013-09-20T09:42:55.448Z"}, {"lat": "44.135702", "lng": "9.682807", "elevation": "87.4000015258789", "time": "2013-09-20T09:42:56.430Z"}, {"lat": "44.13562", "lng": "9.682857", "elevation": "82.0", "time": "2013-09-20T09:43:03.346Z"}, {"lat": "44.135619", "lng": "9.682872", "elevation": "81.5", "time": "2013-09-20T09:43:03.379Z"}, {"lat": "44.13562", "lng": "9.682894", "elevation": "81.69999694824219", "time": "2013-09-20T09:43:08.423Z"}, {"lat": "44.135619", "lng": "9.68289", "elevation": "82.0", "time": "2013-09-20T09:43:09.374Z"}, {"lat": "44.135616", "lng": "9.682886", "elevation": "82.19999694824219", "time": "2013-09-20T09:43:10.438Z"}, {"lat": "44.135614", "lng": "9.682881", "elevation": "82.19999694824219", "time": "2013-09-20T09:43:11.446Z"}, {"lat": "44.135599", "lng": "9.682876", "elevation": "82.0999984741211", "time": "2013-09-20T09:43:17.377Z"}, {"lat": "44.135598", "lng": "9.682876", "elevation": "82.0999984741211", "time": "2013-09-20T09:43:18.486Z"}, {"lat": "44.135599", "lng": "9.682874", "elevation": "82.30000305175781", "time": "2013-09-20T09:44:03.157Z"}, {"lat": "44.135593", "lng": "9.682876", "elevation": "82.30000305175781", "time": "2013-09-20T09:44:03.443Z"}, {"lat": "44.135517", "lng": "9.682874", "elevation": "82.30000305175781", "time": "2013-09-20T09:44:09.412Z"}, {"lat": "44.1355", "lng": "9.682868", "elevation": "82.19999694824219", "time": "2013-09-20T09:44:10.395Z"}, {"lat": "44.135417", "lng": "9.682881", "elevation": "84.5999984741211", "time": "2013-09-20T09:44:14.495Z"}, {"lat": "44.135402", "lng": "9.682891", "elevation": "85.0", "time": "2013-09-20T09:44:15.483Z"}, {"lat": "44.135328", "lng": "9.682879", "elevation": "83.30000305175781", "time": "2013-09-20T09:44:28.361Z"}, {"lat": "44.135333", "lng": "9.682882", "elevation": "83.30000305175781", "time": "2013-09-20T09:44:29.374Z"}, {"lat": "44.135338", "lng": "9.682885", "elevation": "83.30000305175781", "time": "2013-09-20T09:44:30.412Z"}, {"lat": "44.135343", "lng": "9.682889", "elevation": "83.30000305175781", "time": "2013-09-20T09:44:31.399Z"}, {"lat": "44.135358", "lng": "9.682907", "elevation": "83.30000305175781", "time": "2013-09-20T09:44:37.373Z"}, {"lat": "44.134955", "lng": "9.683342", "elevation": "82.30000305175781", "time": "2013-09-20T09:45:28.402Z"}, {"lat": "44.135033", "lng": "9.683385", "elevation": "82.0999984741211", "time": "2013-09-20T09:45:33.739Z"}, {"lat": "44.135044", "lng": "9.683382", "elevation": "82.0999984741211", "time": "2013-09-20T09:45:34.380Z"}, {"lat": "44.135052", "lng": "9.68337", "elevation": "82.19999694824219", "time": "2013-09-20T09:45:39.418Z"}, {"lat": "44.135049", "lng": "9.683368", "elevation": "82.19999694824219", "time": "2013-09-20T09:45:40.395Z"}, {"lat": "44.135041", "lng": "9.683368", "elevation": "82.0999984741211", "time": "2013-09-20T09:45:42.379Z"}, {"lat": "44.135027", "lng": "9.683364", "elevation": "82.0999984741211", "time": "2013-09-20T09:45:43.366Z"}, {"lat": "44.134971", "lng": "9.683342", "elevation": "82.0999984741211", "time": "2013-09-20T09:45:53.383Z"}, {"lat": "44.134971", "lng": "9.683342", "elevation": "82.0999984741211", "time": "2013-09-20T09:45:54.394Z"}, {"lat": "44.134975", "lng": "9.683344", "elevation": "82.0999984741211", "time": "2013-09-20T09:46:03.372Z"}, {"lat": "44.134663", "lng": "9.685106", "elevation": "53.70000076293945", "time": "2013-09-20T11:43:28.836Z"}, {"lat": "44.134807", "lng": "9.685014", "elevation": "31.0", "time": "2013-09-20T11:43:29.744Z"}, {"lat": "44.134857", "lng": "9.68503", "elevation": "39.400001525878906", "time": "2013-09-20T11:43:30.744Z"}, {"lat": "44.134907", "lng": "9.685014", "elevation": "22.299999237060547", "time": "2013-09-20T11:43:31.765Z"}, {"lat": "44.134884", "lng": "9.685022", "elevation": "36.20000076293945", "time": "2013-09-20T11:43:32.744Z"}, {"lat": "44.134806", "lng": "9.684967", "elevation": "65.0", "time": "2013-09-20T11:43:33.745Z"}, {"lat": "44.134806", "lng": "9.684967", "elevation": "65.0", "time": "2013-09-20T11:43:33.845Z"}, {"lat": "44.134683", "lng": "9.685084", "elevation": "65.30000305175781", "time": "2013-09-20T11:43:34.761Z"}, {"lat": "44.134762", "lng": "9.685107", "elevation": "42.70000076293945", "time": "2013-09-20T11:43:35.764Z"}, {"lat": "44.134857", "lng": "9.685136", "elevation": "41.099998474121094", "time": "2013-09-20T11:43:36.749Z"}, {"lat": "44.134875", "lng": "9.685044", "elevation": "59.5", "time": "2013-09-20T11:43:40.751Z"}, {"lat": "44.134842", "lng": "9.68501", "elevation": "51.5", "time": "2013-09-20T11:43:41.759Z"}, {"lat": "44.134779", "lng": "9.684951", "elevation": "56.0", "time": "2013-09-20T11:43:44.756Z"}, {"lat": "44.13472", "lng": "9.684971", "elevation": "65.19999694824219", "time": "2013-09-20T11:43:45.758Z"}, {"lat": "44.13465", "lng": "9.684897", "elevation": "68.5", "time": "2013-09-20T11:44:01.151Z"}, {"lat": "44.134646", "lng": "9.684896", "elevation": "69.30000305175781", "time": "2013-09-20T11:44:02.144Z"}, {"lat": "44.134566", "lng": "9.684845", "elevation": "69.19999694824219", "time": "2013-09-20T11:44:31.143Z"}, {"lat": "44.134553", "lng": "9.684842", "elevation": "69.0999984741211", "time": "2013-09-20T11:44:32.151Z"}, {"lat": "44.134488", "lng": "9.684778", "elevation": "72.9000015258789", "time": "2013-09-20T11:44:39.145Z"}, {"lat": "44.134478", "lng": "9.684769", "elevation": "72.80000305175781", "time": "2013-09-20T11:44:40.148Z"}, {"lat": "44.134453", "lng": "9.684716", "elevation": "71.9000015258789", "time": "2013-09-20T11:44:49.178Z"}, {"lat": "44.134452", "lng": "9.684716", "elevation": "72.0999984741211", "time": "2013-09-20T11:44:50.145Z"}, {"lat": "44.134453", "lng": "9.684705", "elevation": "72.9000015258789", "time": "2013-09-20T11:45:05.201Z"}, {"lat": "44.134451", "lng": "9.684696", "elevation": "74.30000305175781", "time": "2013-09-20T11:45:06.153Z"}, {"lat": "44.134457", "lng": "9.684581", "elevation": "77.19999694824219", "time": "2013-09-20T11:45:19.243Z"}, {"lat": "44.134457", "lng": "9.684581", "elevation": "77.30000305175781", "time": "2013-09-20T11:45:20.223Z"}, {"lat": "44.134455", "lng": "9.684583", "elevation": "77.5", "time": "2013-09-20T11:45:36.233Z"}, {"lat": "44.134449", "lng": "9.684583", "elevation": "78.0999984741211", "time": "2013-09-20T11:45:37.173Z"}, {"lat": "44.134413", "lng": "9.684617", "elevation": "80.4000015258789", "time": "2013-09-20T11:45:43.284Z"}, {"lat": "44.134391", "lng": "9.684664", "elevation": "82.30000305175781", "time": "2013-09-20T11:45:48.165Z"}, {"lat": "44.134324", "lng": "9.684725", "elevation": "79.80000305175781", "time": "2013-09-20T11:46:00.155Z"}, {"lat": "44.134327", "lng": "9.684724", "elevation": "79.9000015258789", "time": "2013-09-20T11:46:01.160Z"}, {"lat": "44.134329", "lng": "9.684725", "elevation": "80.19999694824219", "time": "2013-09-20T11:46:02.155Z"}, {"lat": "44.13434", "lng": "9.68473", "elevation": "80.9000015258789", "time": "2013-09-20T11:46:03.152Z"}, {"lat": "44.134355", "lng": "9.684735", "elevation": "80.69999694824219", "time": "2013-09-20T11:46:06.161Z"}, {"lat": "44.134355", "lng": "9.684736", "elevation": "80.80000305175781", "time": "2013-09-20T11:46:07.157Z"}, {"lat": "44.134354", "lng": "9.684733", "elevation": "81.19999694824219", "time": "2013-09-20T11:46:12.212Z"}, {"lat": "44.134351", "lng": "9.68473", "elevation": "81.19999694824219", "time": "2013-09-20T11:46:13.160Z"}, {"lat": "44.134286", "lng": "9.684733", "elevation": "83.5", "time": "2013-09-20T11:46:27.161Z"}, {"lat": "44.134287", "lng": "9.684733", "elevation": "83.4000015258789", "time": "2013-09-20T11:46:28.168Z"}, {"lat": "44.134277", "lng": "9.684726", "elevation": "87.5999984741211", "time": "2013-09-20T11:48:06.183Z"}, {"lat": "44.134276", "lng": "9.684735", "elevation": "88.5", "time": "2013-09-20T11:48:07.274Z"}, {"lat": "44.134284", "lng": "9.684856", "elevation": "90.0", "time": "2013-09-20T11:48:16.232Z"}, {"lat": "44.134286", "lng": "9.684878", "elevation": "90.5", "time": "2013-09-20T11:48:17.215Z"}, {"lat": "44.134275", "lng": "9.684992", "elevation": "88.9000015258789", "time": "2013-09-20T11:48:23.341Z"}, {"lat": "44.134271", "lng": "9.685005", "elevation": "88.30000305175781", "time": "2013-09-20T11:48:24.244Z"}, {"lat": "44.134207", "lng": "9.685056", "elevation": "88.19999694824219", "time": "2013-09-20T11:48:37.186Z"}, {"lat": "44.134207", "lng": "9.685055", "elevation": "88.19999694824219", "time": "2013-09-20T11:48:38.203Z"}, {"lat": "44.134212", "lng": "9.685062", "elevation": "88.4000015258789", "time": "2013-09-20T11:48:45.212Z"}, {"lat": "44.134217", "lng": "9.685065", "elevation": "87.80000305175781", "time": "2013-09-20T11:48:46.171Z"}, {"lat": "44.134234", "lng": "9.68509", "elevation": "87.0999984741211", "time": "2013-09-20T11:48:53.125Z"}, {"lat": "44.134234", "lng": "9.68509", "elevation": "86.80000305175781", "time": "2013-09-20T11:48:53.208Z"}, {"lat": "44.13423", "lng": "9.685092", "elevation": "87.0", "time": "2013-09-20T11:48:56.175Z"}, {"lat": "44.134225", "lng": "9.685089", "elevation": "86.5", "time": "2013-09-20T11:48:57.241Z"}, {"lat": "44.134191", "lng": "9.685074", "elevation": "90.30000305175781", "time": "2013-09-20T11:49:07.183Z"}, {"lat": "44.13419", "lng": "9.685075", "elevation": "90.19999694824219", "time": "2013-09-20T11:49:08.182Z"}, {"lat": "44.134185", "lng": "9.685077", "elevation": "91.0999984741211", "time": "2013-09-20T11:49:14.181Z"}, {"lat": "44.134182", "lng": "9.685085", "elevation": "90.69999694824219", "time": "2013-09-20T11:49:15.193Z"}, {"lat": "44.134132", "lng": "9.685179", "elevation": "91.0999984741211", "time": "2013-09-20T11:49:23.282Z"}, {"lat": "44.13413", "lng": "9.685195", "elevation": "91.0", "time": "2013-09-20T11:49:24.179Z"}, {"lat": "44.134134", "lng": "9.685243", "elevation": "92.5", "time": "2013-09-20T11:49:30.174Z"}, {"lat": "44.134135", "lng": "9.685239", "elevation": "92.4000015258789", "time": "2013-09-20T11:49:31.178Z"}, {"lat": "44.134131", "lng": "9.685253", "elevation": "94.0", "time": "2013-09-20T11:50:03.199Z"}, {"lat": "44.134127", "lng": "9.685259", "elevation": "94.5", "time": "2013-09-20T11:50:04.179Z"}, {"lat": "44.134111", "lng": "9.685357", "elevation": "98.0999984741211", "time": "2013-09-20T11:50:16.243Z"}, {"lat": "44.13411", "lng": "9.685357", "elevation": "98.30000305175781", "time": "2013-09-20T11:50:17.221Z"}, {"lat": "44.134101", "lng": "9.685357", "elevation": "99.5", "time": "2013-09-20T11:50:28.418Z"}, {"lat": "44.134095", "lng": "9.685358", "elevation": "100.0999984741211", "time": "2013-09-20T11:50:29.194Z"}, {"lat": "44.13401", "lng": "9.685381", "elevation": "100.69999694824219", "time": "2013-09-20T11:50:38.677Z"}, {"lat": "44.134001", "lng": "9.685388", "elevation": "99.80000305175781", "time": "2013-09-20T11:50:39.276Z"}, {"lat": "44.133965", "lng": "9.685502", "elevation": "90.30000305175781", "time": "2013-09-20T11:50:44.181Z"}, {"lat": "44.133962", "lng": "9.685525", "elevation": "90.0", "time": "2013-09-20T11:50:45.215Z"}, {"lat": "44.133912", "lng": "9.68562", "elevation": "91.0", "time": "2013-09-20T11:50:53.178Z"}, {"lat": "44.133905", "lng": "9.685635", "elevation": "90.80000305175781", "time": "2013-09-20T11:50:54.180Z"}, {"lat": "44.133842", "lng": "9.685708", "elevation": "91.80000305175781", "time": "2013-09-20T11:51:01.181Z"}, {"lat": "44.133834", "lng": "9.685717", "elevation": "90.69999694824219", "time": "2013-09-20T11:51:02.196Z"}, {"lat": "44.133794", "lng": "9.685815", "elevation": "90.5999984741211", "time": "2013-09-20T11:51:10.184Z"}, {"lat": "44.133788", "lng": "9.685826", "elevation": "91.5999984741211", "time": "2013-09-20T11:51:11.186Z"}, {"lat": "44.133727", "lng": "9.685894", "elevation": "96.0999984741211", "time": "2013-09-20T11:51:17.190Z"}, {"lat": "44.133715", "lng": "9.685901", "elevation": "95.5", "time": "2013-09-20T11:51:18.182Z"}, {"lat": "44.133657", "lng": "9.685932", "elevation": "98.5", "time": "2013-09-20T11:51:28.938Z"}, {"lat": "44.133658", "lng": "9.68593", "elevation": "99.69999694824219", "time": "2013-09-20T11:51:29.213Z"}, {"lat": "44.133655", "lng": "9.685926", "elevation": "101.0", "time": "2013-09-20T11:51:30.182Z"}, {"lat": "44.133635", "lng": "9.685912", "elevation": "103.0", "time": "2013-09-20T11:51:37.203Z"}, {"lat": "44.133633", "lng": "9.685913", "elevation": "103.69999694824219", "time": "2013-09-20T11:51:38.197Z"}, {"lat": "44.133632", "lng": "9.685919", "elevation": "110.4000015258789", "time": "2013-09-20T11:51:47.194Z"}, {"lat": "44.133627", "lng": "9.685926", "elevation": "110.5", "time": "2013-09-20T11:51:48.197Z"}, {"lat": "44.133579", "lng": "9.686024", "elevation": "112.0", "time": "2013-09-20T11:51:58.253Z"}, {"lat": "44.133574", "lng": "9.68603", "elevation": "112.9000015258789", "time": "2013-09-20T11:51:59.286Z"}, {"lat": "44.13351", "lng": "9.686115", "elevation": "113.19999694824219", "time": "2013-09-20T11:52:15.260Z"}, {"lat": "44.133508", "lng": "9.686117", "elevation": "111.4000015258789", "time": "2013-09-20T11:52:16.195Z"}, {"lat": "44.133449", "lng": "9.6862", "elevation": "120.0999984741211", "time": "2013-09-20T11:52:30.195Z"}, {"lat": "44.133443", "lng": "9.686208", "elevation": "119.69999694824219", "time": "2013-09-20T11:52:31.202Z"}, {"lat": "44.133378", "lng": "9.68628", "elevation": "124.69999694824219", "time": "2013-09-20T11:52:41.234Z"}, {"lat": "44.133366", "lng": "9.686279", "elevation": "125.19999694824219", "time": "2013-09-20T11:52:42.203Z"}, {"lat": "44.133279", "lng": "9.68631", "elevation": "125.80000305175781", "time": "2013-09-20T11:52:51.199Z"}, {"lat": "44.133273", "lng": "9.686313", "elevation": "126.0999984741211", "time": "2013-09-20T11:52:52.207Z"}, {"lat": "44.133205", "lng": "9.686391", "elevation": "129.89999389648438", "time": "2013-09-20T11:53:05.190Z"}, {"lat": "44.133198", "lng": "9.686383", "elevation": "129.6999969482422", "time": "2013-09-20T11:53:06.199Z"}, {"lat": "44.133194", "lng": "9.686363", "elevation": "129.39999389648438", "time": "2013-09-20T11:53:11.197Z"}, {"lat": "44.133194", "lng": "9.686364", "elevation": "128.89999389648438", "time": "2013-09-20T11:53:12.211Z"}, {"lat": "44.133195", "lng": "9.686378", "elevation": "129.10000610351563", "time": "2013-09-20T11:53:15.348Z"}, {"lat": "44.133196", "lng": "9.686384", "elevation": "128.6999969482422", "time": "2013-09-20T11:53:16.197Z"}, {"lat": "44.133205", "lng": "9.68641", "elevation": "129.5", "time": "2013-09-20T11:53:22.202Z"}, {"lat": "44.133205", "lng": "9.68641", "elevation": "129.5", "time": "2013-09-20T11:53:23.205Z"}, {"lat": "44.133202", "lng": "9.686414", "elevation": "128.60000610351563", "time": "2013-09-20T11:53:49.203Z"}, {"lat": "44.133203", "lng": "9.686419", "elevation": "128.39999389648438", "time": "2013-09-20T11:53:50.325Z"}, {"lat": "44.133202", "lng": "9.686527", "elevation": "126.5999984741211", "time": "2013-09-20T11:54:00.263Z"}, {"lat": "44.133202", "lng": "9.686549", "elevation": "125.69999694824219", "time": "2013-09-20T11:54:01.240Z"}, {"lat": "44.133192", "lng": "9.686659", "elevation": "127.30000305175781", "time": "2013-09-20T11:54:06.214Z"}, {"lat": "44.133187", "lng": "9.686677", "elevation": "127.0", "time": "2013-09-20T11:54:07.201Z"}, {"lat": "44.133136", "lng": "9.686765", "elevation": "129.1999969482422", "time": "2013-09-20T11:54:14.205Z"}, {"lat": "44.133128", "lng": "9.686776", "elevation": "129.3000030517578", "time": "2013-09-20T11:54:15.298Z"}, {"lat": "44.133068", "lng": "9.686852", "elevation": "131.10000610351563", "time": "2013-09-20T11:54:23.211Z"}, {"lat": "44.133064", "lng": "9.686867", "elevation": "131.0", "time": "2013-09-20T11:54:24.209Z"}, {"lat": "44.133024", "lng": "9.686974", "elevation": "128.60000610351563", "time": "2013-09-20T11:54:33.237Z"}, {"lat": "44.133018", "lng": "9.686986", "elevation": "128.5", "time": "2013-09-20T11:54:34.206Z"}, {"lat": "44.132967", "lng": "9.687078", "elevation": "131.1999969482422", "time": "2013-09-20T11:54:47.329Z"}, {"lat": "44.132962", "lng": "9.687087", "elevation": "129.8000030517578", "time": "2013-09-20T11:54:48.300Z"}, {"lat": "44.132916", "lng": "9.68719", "elevation": "128.8000030517578", "time": "2013-09-20T11:54:55.296Z"}, {"lat": "44.132911", "lng": "9.6872", "elevation": "128.89999389648438", "time": "2013-09-20T11:54:56.281Z"}, {"lat": "44.132873", "lng": "9.6873", "elevation": "130.1999969482422", "time": "2013-09-20T11:55:06.211Z"}, {"lat": "44.132865", "lng": "9.687314", "elevation": "131.39999389648438", "time": "2013-09-20T11:55:07.215Z"}, {"lat": "44.13282", "lng": "9.687412", "elevation": "134.1999969482422", "time": "2013-09-20T11:55:14.225Z"}, {"lat": "44.132812", "lng": "9.687425", "elevation": "134.5", "time": "2013-09-20T11:55:15.211Z"}, {"lat": "44.132782", "lng": "9.687533", "elevation": "130.5", "time": "2013-09-20T11:55:22.210Z"}, {"lat": "44.132784", "lng": "9.687551", "elevation": "130.89999389648438", "time": "2013-09-20T11:55:23.215Z"}, {"lat": "44.132749", "lng": "9.687664", "elevation": "133.6999969482422", "time": "2013-09-20T11:55:31.210Z"}, {"lat": "44.132745", "lng": "9.68768", "elevation": "134.1999969482422", "time": "2013-09-20T11:55:32.223Z"}, {"lat": "44.132741", "lng": "9.687762", "elevation": "133.89999389648438", "time": "2013-09-20T11:55:43.210Z"}, {"lat": "44.132742", "lng": "9.687762", "elevation": "134.3000030517578", "time": "2013-09-20T11:55:44.224Z"}, {"lat": "44.13274", "lng": "9.687767", "elevation": "135.10000610351563", "time": "2013-09-20T11:55:47.211Z"}, {"lat": "44.132738", "lng": "9.687772", "elevation": "136.39999389648438", "time": "2013-09-20T11:55:48.204Z"}, {"lat": "44.132731", "lng": "9.687895", "elevation": "138.1999969482422", "time": "2013-09-20T11:56:00.256Z"}, {"lat": "44.132735", "lng": "9.687903", "elevation": "137.6999969482422", "time": "2013-09-20T11:56:01.214Z"}, {"lat": "44.132757", "lng": "9.688023", "elevation": "137.6999969482422", "time": "2013-09-20T11:56:13.312Z"}, {"lat": "44.132754", "lng": "9.688027", "elevation": "138.3000030517578", "time": "2013-09-20T11:56:14.220Z"}, {"lat": "44.132759", "lng": "9.688064", "elevation": "141.3000030517578", "time": "2013-09-20T11:56:24.216Z"}, {"lat": "44.132759", "lng": "9.688065", "elevation": "141.3000030517578", "time": "2013-09-20T11:56:25.213Z"}, {"lat": "44.13275", "lng": "9.688102", "elevation": "143.39999389648438", "time": "2013-09-20T11:56:49.219Z"}, {"lat": "44.13275", "lng": "9.688108", "elevation": "143.3000030517578", "time": "2013-09-20T11:56:50.290Z"}, {"lat": "44.132754", "lng": "9.688224", "elevation": "144.1999969482422", "time": "2013-09-20T11:56:57.274Z"}, {"lat": "44.132755", "lng": "9.688243", "elevation": "144.39999389648438", "time": "2013-09-20T11:56:58.229Z"}, {"lat": "44.132775", "lng": "9.688359", "elevation": "141.8000030517578", "time": "2013-09-20T11:57:05.219Z"}, {"lat": "44.132778", "lng": "9.688378", "elevation": "141.5", "time": "2013-09-20T11:57:06.218Z"}, {"lat": "44.132775", "lng": "9.688494", "elevation": "142.0", "time": "2013-09-20T11:57:12.226Z"}, {"lat": "44.132773", "lng": "9.688514", "elevation": "140.8000030517578", "time": "2013-09-20T11:57:13.327Z"}, {"lat": "44.132758", "lng": "9.688635", "elevation": "142.39999389648438", "time": "2013-09-20T11:57:19.222Z"}, {"lat": "44.132756", "lng": "9.688659", "elevation": "142.39999389648438", "time": "2013-09-20T11:57:20.225Z"}, {"lat": "44.132744", "lng": "9.688781", "elevation": "142.3000030517578", "time": "2013-09-20T11:57:25.257Z"}, {"lat": "44.132741", "lng": "9.688806", "elevation": "142.5", "time": "2013-09-20T11:57:26.309Z"}, {"lat": "44.132725", "lng": "9.688919", "elevation": "141.6999969482422", "time": "2013-09-20T11:57:31.226Z"}, {"lat": "44.132725", "lng": "9.688943", "elevation": "141.10000610351563", "time": "2013-09-20T11:57:32.270Z"}, {"lat": "44.132733", "lng": "9.689059", "elevation": "138.89999389648438", "time": "2013-09-20T11:57:37.226Z"}, {"lat": "44.132738", "lng": "9.689083", "elevation": "139.39999389648438", "time": "2013-09-20T11:57:38.218Z"}, {"lat": "44.132716", "lng": "9.689201", "elevation": "137.89999389648438", "time": "2013-09-20T11:57:45.262Z"}, {"lat": "44.132707", "lng": "9.689214", "elevation": "138.6999969482422", "time": "2013-09-20T11:57:46.421Z"}, {"lat": "44.13265", "lng": "9.689307", "elevation": "137.3000030517578", "time": "2013-09-20T11:58:02.222Z"}, {"lat": "44.132656", "lng": "9.689324", "elevation": "137.8000030517578", "time": "2013-09-20T11:58:03.306Z"}, {"lat": "44.13269", "lng": "9.689431", "elevation": "135.6999969482422", "time": "2013-09-20T11:58:11.338Z"}, {"lat": "44.132692", "lng": "9.689446", "elevation": "134.89999389648438", "time": "2013-09-20T11:58:12.383Z"}, {"lat": "44.132681", "lng": "9.689563", "elevation": "135.1999969482422", "time": "2013-09-20T11:58:20.266Z"}, {"lat": "44.132678", "lng": "9.689578", "elevation": "135.1999969482422", "time": "2013-09-20T11:58:21.231Z"}, {"lat": "44.13266", "lng": "9.689694", "elevation": "137.10000610351563", "time": "2013-09-20T11:58:30.227Z"}, {"lat": "44.132654", "lng": "9.689707", "elevation": "136.60000610351563", "time": "2013-09-20T11:58:31.226Z"}, {"lat": "44.132598", "lng": "9.689803", "elevation": "138.39999389648438", "time": "2013-09-20T11:58:39.221Z"}, {"lat": "44.132596", "lng": "9.689812", "elevation": "138.10000610351563", "time": "2013-09-20T11:58:40.275Z"}, {"lat": "44.132594", "lng": "9.689823", "elevation": "137.89999389648438", "time": "2013-09-20T11:58:45.241Z"}, {"lat": "44.132593", "lng": "9.689823", "elevation": "138.39999389648438", "time": "2013-09-20T11:58:46.230Z"}, {"lat": "44.132585", "lng": "9.689827", "elevation": "138.3000030517578", "time": "2013-09-20T11:58:55.225Z"}, {"lat": "44.132582", "lng": "9.689834", "elevation": "137.89999389648438", "time": "2013-09-20T11:58:56.231Z"}, {"lat": "44.132518", "lng": "9.689917", "elevation": "139.1999969482422", "time": "2013-09-20T11:59:03.223Z"}, {"lat": "44.132503", "lng": "9.689923", "elevation": "139.1999969482422", "time": "2013-09-20T11:59:04.391Z"}, {"lat": "44.132441", "lng": "9.689981", "elevation": "135.5", "time": "2013-09-20T11:59:10.226Z"}, {"lat": "44.13243", "lng": "9.689998", "elevation": "136.39999389648438", "time": "2013-09-20T11:59:11.227Z"}, {"lat": "44.132368", "lng": "9.690086", "elevation": "136.89999389648438", "time": "2013-09-20T11:59:16.265Z"}, {"lat": "44.132359", "lng": "9.690106", "elevation": "137.6999969482422", "time": "2013-09-20T11:59:17.276Z"}, {"lat": "44.132334", "lng": "9.690212", "elevation": "133.1999969482422", "time": "2013-09-20T11:59:22.229Z"}, {"lat": "44.132329", "lng": "9.690232", "elevation": "133.89999389648438", "time": "2013-09-20T11:59:23.234Z"}, {"lat": "44.132301", "lng": "9.690341", "elevation": "130.0", "time": "2013-09-20T11:59:30.317Z"}, {"lat": "44.132303", "lng": "9.690363", "elevation": "130.3000030517578", "time": "2013-09-20T11:59:31.239Z"}, {"lat": "44.132272", "lng": "9.690465", "elevation": "127.9000015258789", "time": "2013-09-20T11:59:38.243Z"}, {"lat": "44.132265", "lng": "9.690477", "elevation": "129.60000610351563", "time": "2013-09-20T11:59:39.334Z"}, {"lat": "44.132224", "lng": "9.690581", "elevation": "129.39999389648438", "time": "2013-09-20T11:59:48.453Z"}, {"lat": "44.132226", "lng": "9.690597", "elevation": "128.8000030517578", "time": "2013-09-20T11:59:49.327Z"}, {"lat": "44.132231", "lng": "9.690711", "elevation": "127.19999694824219", "time": "2013-09-20T11:59:56.311Z"}, {"lat": "44.132231", "lng": "9.690723", "elevation": "125.9000015258789", "time": "2013-09-20T11:59:57.255Z"}, {"lat": "44.13221", "lng": "9.690783", "elevation": "129.0", "time": "2013-09-20T12:00:11.240Z"}, {"lat": "44.132213", "lng": "9.690787", "elevation": "129.0", "time": "2013-09-20T12:00:12.304Z"}, {"lat": "44.132218", "lng": "9.690793", "elevation": "128.60000610351563", "time": "2013-09-20T12:00:13.262Z"}, {"lat": "44.132238", "lng": "9.690817", "elevation": "128.10000610351563", "time": "2013-09-20T12:00:20.231Z"}, {"lat": "44.132239", "lng": "9.690817", "elevation": "128.1999969482422", "time": "2013-09-20T12:00:21.233Z"}, {"lat": "44.132235", "lng": "9.690816", "elevation": "128.1999969482422", "time": "2013-09-20T12:00:31.234Z"}, {"lat": "44.132228", "lng": "9.690816", "elevation": "128.5", "time": "2013-09-20T12:00:32.233Z"}, {"lat": "44.132147", "lng": "9.690857", "elevation": "129.8000030517578", "time": "2013-09-20T12:00:38.262Z"}, {"lat": "44.132133", "lng": "9.690872", "elevation": "130.5", "time": "2013-09-20T12:00:39.241Z"}, {"lat": "44.132094", "lng": "9.690973", "elevation": "131.10000610351563", "time": "2013-09-20T12:00:44.244Z"}, {"lat": "44.132088", "lng": "9.690988", "elevation": "131.3000030517578", "time": "2013-09-20T12:00:45.234Z"}, {"lat": "44.132052", "lng": "9.691091", "elevation": "130.8000030517578", "time": "2013-09-20T12:00:55.233Z"}, {"lat": "44.132049", "lng": "9.691105", "elevation": "131.60000610351563", "time": "2013-09-20T12:00:56.232Z"}, {"lat": "44.132004", "lng": "9.691212", "elevation": "131.39999389648438", "time": "2013-09-20T12:01:03.239Z"}, {"lat": "44.131997", "lng": "9.691229", "elevation": "131.3000030517578", "time": "2013-09-20T12:01:04.244Z"}, {"lat": "44.13198", "lng": "9.69126", "elevation": "131.0", "time": "2013-09-20T12:01:06.256Z"}, {"lat": "44.131924", "lng": "9.691412", "elevation": "132.6999969482422", "time": "2013-09-20T12:01:16.223Z"}, {"lat": "44.131908", "lng": "9.691519", "elevation": "131.89999389648438", "time": "2013-09-20T12:01:22.282Z"}, {"lat": "44.131905", "lng": "9.691535", "elevation": "131.60000610351563", "time": "2013-09-20T12:01:23.256Z"}, {"lat": "44.131852", "lng": "9.691635", "elevation": "133.10000610351563", "time": "2013-09-20T12:01:32.270Z"}, {"lat": "44.131838", "lng": "9.691635", "elevation": "133.8000030517578", "time": "2013-09-20T12:01:33.237Z"}, {"lat": "44.131776", "lng": "9.691718", "elevation": "134.10000610351563", "time": "2013-09-20T12:01:42.268Z"}, {"lat": "44.131766", "lng": "9.691726", "elevation": "134.0", "time": "2013-09-20T12:01:43.254Z"}, {"lat": "44.131685", "lng": "9.691775", "elevation": "133.39999389648438", "time": "2013-09-20T12:01:50.249Z"}, {"lat": "44.131671", "lng": "9.691779", "elevation": "132.60000610351563", "time": "2013-09-20T12:01:51.242Z"}, {"lat": "44.131625", "lng": "9.691876", "elevation": "129.89999389648438", "time": "2013-09-20T12:01:59.401Z"}, {"lat": "44.13162", "lng": "9.691888", "elevation": "130.5", "time": "2013-09-20T12:02:00.452Z"}, {"lat": "44.13156", "lng": "9.691973", "elevation": "133.1999969482422", "time": "2013-09-20T12:02:09.242Z"}, {"lat": "44.131555", "lng": "9.691984", "elevation": "133.39999389648438", "time": "2013-09-20T12:02:10.252Z"}, {"lat": "44.13151", "lng": "9.692083", "elevation": "133.6999969482422", "time": "2013-09-20T12:02:19.252Z"}, {"lat": "44.131508", "lng": "9.692097", "elevation": "133.8000030517578", "time": "2013-09-20T12:02:20.245Z"}, {"lat": "44.13145", "lng": "9.692182", "elevation": "134.3000030517578", "time": "2013-09-20T12:02:29.238Z"}, {"lat": "44.131441", "lng": "9.692189", "elevation": "134.39999389648438", "time": "2013-09-20T12:02:30.245Z"}, {"lat": "44.131361", "lng": "9.692245", "elevation": "140.89999389648438", "time": "2013-09-20T12:02:40.358Z"}, {"lat": "44.131355", "lng": "9.69225", "elevation": "140.6999969482422", "time": "2013-09-20T12:02:41.279Z"}, {"lat": "44.131277", "lng": "9.692304", "elevation": "144.1999969482422", "time": "2013-09-20T12:02:53.277Z"}, {"lat": "44.131271", "lng": "9.692311", "elevation": "143.89999389648438", "time": "2013-09-20T12:02:54.368Z"}, {"lat": "44.131207", "lng": "9.692396", "elevation": "149.89999389648438", "time": "2013-09-20T12:03:07.248Z"}, {"lat": "44.131205", "lng": "9.692406", "elevation": "149.60000610351563", "time": "2013-09-20T12:03:08.265Z"}, {"lat": "44.1312", "lng": "9.692455", "elevation": "149.8000030517578", "time": "2013-09-20T12:03:15.265Z"}, {"lat": "44.131202", "lng": "9.692456", "elevation": "149.60000610351563", "time": "2013-09-20T12:03:16.256Z"}, {"lat": "44.131204", "lng": "9.692461", "elevation": "149.5", "time": "2013-09-20T12:03:19.361Z"}, {"lat": "44.131203", "lng": "9.692466", "elevation": "149.6999969482422", "time": "2013-09-20T12:03:20.312Z"}, {"lat": "44.131145", "lng": "9.692559", "elevation": "153.0", "time": "2013-09-20T12:03:32.242Z"}, {"lat": "44.131137", "lng": "9.692568", "elevation": "152.8000030517578", "time": "2013-09-20T12:03:33.275Z"}, {"lat": "44.131071", "lng": "9.692643", "elevation": "153.89999389648438", "time": "2013-09-20T12:03:45.243Z"}, {"lat": "44.131065", "lng": "9.692646", "elevation": "154.8000030517578", "time": "2013-09-20T12:03:46.251Z"}, {"lat": "44.131004", "lng": "9.692735", "elevation": "162.6999969482422", "time": "2013-09-20T12:04:00.249Z"}, {"lat": "44.130998", "lng": "9.692735", "elevation": "161.89999389648438", "time": "2013-09-20T12:04:01.252Z"}, {"lat": "44.130974", "lng": "9.69277", "elevation": "162.8000030517578", "time": "2013-09-20T12:04:10.244Z"}, {"lat": "44.130975", "lng": "9.692769", "elevation": "163.6999969482422", "time": "2013-09-20T12:04:11.252Z"}, {"lat": "44.13096", "lng": "9.692758", "elevation": "165.60000610351563", "time": "2013-09-20T12:05:04.248Z"}, {"lat": "44.130953", "lng": "9.692763", "elevation": "165.1999969482422", "time": "2013-09-20T12:05:05.256Z"}, {"lat": "44.130945", "lng": "9.692876", "elevation": "160.10000610351563", "time": "2013-09-20T12:05:14.265Z"}, {"lat": "44.130943", "lng": "9.692887", "elevation": "160.5", "time": "2013-09-20T12:05:15.256Z"}, {"lat": "44.130979", "lng": "9.692999", "elevation": "169.10000610351563", "time": "2013-09-20T12:05:39.270Z"}, {"lat": "44.130976", "lng": "9.693003", "elevation": "169.89999389648438", "time": "2013-09-20T12:05:40.264Z"}, {"lat": "44.130921", "lng": "9.693018", "elevation": "171.39999389648438", "time": "2013-09-20T12:05:50.347Z"}, {"lat": "44.13092", "lng": "9.693017", "elevation": "172.3000030517578", "time": "2013-09-20T12:05:51.355Z"}, {"lat": "44.130914", "lng": "9.693011", "elevation": "172.89999389648438", "time": "2013-09-20T12:06:20.277Z"}, {"lat": "44.130908", "lng": "9.693012", "elevation": "173.89999389648438", "time": "2013-09-20T12:06:21.281Z"}, {"lat": "44.130823", "lng": "9.693026", "elevation": "172.5", "time": "2013-09-20T12:06:28.273Z"}, {"lat": "44.13081", "lng": "9.693039", "elevation": "170.3000030517578", "time": "2013-09-20T12:06:29.270Z"}, {"lat": "44.130792", "lng": "9.693152", "elevation": "166.39999389648438", "time": "2013-09-20T12:06:33.302Z"}, {"lat": "44.130789", "lng": "9.693182", "elevation": "165.89999389648438", "time": "2013-09-20T12:06:34.265Z"}, {"lat": "44.130722", "lng": "9.693263", "elevation": "166.6999969482422", "time": "2013-09-20T12:06:42.283Z"}, {"lat": "44.130721", "lng": "9.69327", "elevation": "166.8000030517578", "time": "2013-09-20T12:06:43.292Z"}, {"lat": "44.130718", "lng": "9.69328", "elevation": "167.5", "time": "2013-09-20T12:06:48.361Z"}, {"lat": "44.130717", "lng": "9.693279", "elevation": "167.39999389648438", "time": "2013-09-20T12:06:49.323Z"}, {"lat": "44.130711", "lng": "9.693278", "elevation": "168.39999389648438", "time": "2013-09-20T12:06:52.273Z"}, {"lat": "44.130706", "lng": "9.693278", "elevation": "168.8000030517578", "time": "2013-09-20T12:06:53.377Z"}, {"lat": "44.130619", "lng": "9.69328", "elevation": "174.5", "time": "2013-09-20T12:07:06.282Z"}, {"lat": "44.130612", "lng": "9.693275", "elevation": "174.6999969482422", "time": "2013-09-20T12:07:07.273Z"}, {"lat": "44.130602", "lng": "9.693267", "elevation": "174.89999389648438", "time": "2013-09-20T12:07:12.271Z"}, {"lat": "44.130603", "lng": "9.693267", "elevation": "174.89999389648438", "time": "2013-09-20T12:07:13.263Z"}, {"lat": "44.130599", "lng": "9.693273", "elevation": "178.1999969482422", "time": "2013-09-20T12:07:58.269Z"}, {"lat": "44.130594", "lng": "9.693271", "elevation": "179.5", "time": "2013-09-20T12:07:59.267Z"}, {"lat": "44.130574", "lng": "9.693262", "elevation": "180.1999969482422", "time": "2013-09-20T12:08:06.271Z"}, {"lat": "44.130573", "lng": "9.693263", "elevation": "180.3000030517578", "time": "2013-09-20T12:08:07.271Z"}, {"lat": "44.130558", "lng": "9.693261", "elevation": "180.5", "time": "2013-09-20T12:09:44.286Z"}, {"lat": "44.130556", "lng": "9.69326", "elevation": "180.8000030517578", "time": "2013-09-20T12:09:45.282Z"}, {"lat": "44.13054", "lng": "9.693267", "elevation": "180.5", "time": "2013-09-20T12:09:51.288Z"}, {"lat": "44.130539", "lng": "9.693268", "elevation": "180.60000610351563", "time": "2013-09-20T12:09:52.279Z"}, {"lat": "44.130536", "lng": "9.693273", "elevation": "180.89999389648438", "time": "2013-09-20T12:10:40.324Z"}, {"lat": "44.130534", "lng": "9.693277", "elevation": "181.0", "time": "2013-09-20T12:10:41.273Z"}, {"lat": "44.130497", "lng": "9.693262", "elevation": "184.0", "time": "2013-09-20T12:10:49.271Z"}, {"lat": "44.130496", "lng": "9.693261", "elevation": "184.0", "time": "2013-09-20T12:10:50.323Z"}, {"lat": "44.130496", "lng": "9.693252", "elevation": "186.10000610351563", "time": "2013-09-20T12:11:13.302Z"}, {"lat": "44.130495", "lng": "9.693244", "elevation": "185.6999969482422", "time": "2013-09-20T12:11:14.285Z"}, {"lat": "44.13048", "lng": "9.693198", "elevation": "189.6999969482422", "time": "2013-09-20T12:11:24.287Z"}, {"lat": "44.13048", "lng": "9.693199", "elevation": "189.1999969482422", "time": "2013-09-20T12:11:25.286Z"}, {"lat": "44.130479", "lng": "9.693214", "elevation": "192.39999389648438", "time": "2013-09-20T12:11:39.289Z"}, {"lat": "44.130476", "lng": "9.693218", "elevation": "190.6999969482422", "time": "2013-09-20T12:11:40.286Z"}, {"lat": "44.130508", "lng": "9.693334", "elevation": "197.5", "time": "2013-09-20T12:11:52.324Z"}, {"lat": "44.130514", "lng": "9.693345", "elevation": "197.1999969482422", "time": "2013-09-20T12:11:53.332Z"}, {"lat": "44.130525", "lng": "9.693463", "elevation": "196.10000610351563", "time": "2013-09-20T12:12:04.317Z"}, {"lat": "44.130519", "lng": "9.693474", "elevation": "196.60000610351563", "time": "2013-09-20T12:12:05.373Z"}, {"lat": "44.13049", "lng": "9.693587", "elevation": "198.6999969482422", "time": "2013-09-20T12:12:19.306Z"}, {"lat": "44.13049", "lng": "9.693596", "elevation": "199.3000030517578", "time": "2013-09-20T12:12:20.297Z"}, {"lat": "44.130512", "lng": "9.693715", "elevation": "200.0", "time": "2013-09-20T12:12:34.299Z"}, {"lat": "44.130511", "lng": "9.693722", "elevation": "200.0", "time": "2013-09-20T12:12:35.307Z"}, {"lat": "44.130487", "lng": "9.693839", "elevation": "203.6999969482422", "time": "2013-09-20T12:12:51.308Z"}, {"lat": "44.130481", "lng": "9.693851", "elevation": "204.60000610351563", "time": "2013-09-20T12:12:52.298Z"}, {"lat": "44.130447", "lng": "9.693964", "elevation": "207.5", "time": "2013-09-20T12:13:03.396Z"}, {"lat": "44.130444", "lng": "9.693975", "elevation": "208.3000030517578", "time": "2013-09-20T12:13:04.382Z"}, {"lat": "44.130406", "lng": "9.69408", "elevation": "210.10000610351563", "time": "2013-09-20T12:13:12.317Z"}, {"lat": "44.130399", "lng": "9.694092", "elevation": "210.1999969482422", "time": "2013-09-20T12:13:13.334Z"}, {"lat": "44.130349", "lng": "9.694189", "elevation": "213.1999969482422", "time": "2013-09-20T12:13:22.314Z"}, {"lat": "44.130347", "lng": "9.694202", "elevation": "213.6999969482422", "time": "2013-09-20T12:13:23.311Z"}, {"lat": "44.130305", "lng": "9.6943", "elevation": "217.39999389648438", "time": "2013-09-20T12:13:33.398Z"}, {"lat": "44.130299", "lng": "9.694309", "elevation": "217.1999969482422", "time": "2013-09-20T12:13:34.295Z"}, {"lat": "44.13023", "lng": "9.694378", "elevation": "217.8000030517578", "time": "2013-09-20T12:13:42.425Z"}, {"lat": "44.130222", "lng": "9.694384", "elevation": "216.3000030517578", "time": "2013-09-20T12:13:43.388Z"}, {"lat": "44.130217", "lng": "9.694383", "elevation": "217.60000610351563", "time": "2013-09-20T12:13:47.297Z"}, {"lat": "44.130218", "lng": "9.694382", "elevation": "217.89999389648438", "time": "2013-09-20T12:13:48.305Z"}, {"lat": "44.130224", "lng": "9.694398", "elevation": "218.6999969482422", "time": "2013-09-20T12:14:10.330Z"}, {"lat": "44.13022", "lng": "9.694404", "elevation": "219.8000030517578", "time": "2013-09-20T12:14:11.311Z"}, {"lat": "44.130142", "lng": "9.694452", "elevation": "222.10000610351563", "time": "2013-09-20T12:14:17.301Z"}, {"lat": "44.130127", "lng": "9.694465", "elevation": "223.0", "time": "2013-09-20T12:14:18.305Z"}, {"lat": "44.130056", "lng": "9.694534", "elevation": "228.10000610351563", "time": "2013-09-20T12:14:23.410Z"}, {"lat": "44.130044", "lng": "9.694544", "elevation": "229.39999389648438", "time": "2013-09-20T12:14:24.362Z"}, {"lat": "44.130043", "lng": "9.694603", "elevation": "229.6999969482422", "time": "2013-09-20T12:14:34.310Z"}, {"lat": "44.130043", "lng": "9.694603", "elevation": "229.8000030517578", "time": "2013-09-20T12:14:35.301Z"}, {"lat": "44.13004", "lng": "9.694613", "elevation": "231.89999389648438", "time": "2013-09-20T12:14:48.355Z"}, {"lat": "44.130038", "lng": "9.694621", "elevation": "233.10000610351563", "time": "2013-09-20T12:14:49.341Z"}, {"lat": "44.13003", "lng": "9.69474", "elevation": "231.3000030517578", "time": "2013-09-20T12:14:56.306Z"}, {"lat": "44.130032", "lng": "9.694756", "elevation": "231.5", "time": "2013-09-20T12:14:57.298Z"}, {"lat": "44.130048", "lng": "9.694868", "elevation": "234.60000610351563", "time": "2013-09-20T12:15:09.300Z"}, {"lat": "44.13005", "lng": "9.694878", "elevation": "234.5", "time": "2013-09-20T12:15:10.323Z"}, {"lat": "44.130062", "lng": "9.695001", "elevation": "240.39999389648438", "time": "2013-09-20T12:15:24.409Z"}, {"lat": "44.130061", "lng": "9.695013", "elevation": "239.60000610351563", "time": "2013-09-20T12:15:25.381Z"}, {"lat": "44.130046", "lng": "9.695119", "elevation": "242.5", "time": "2013-09-20T12:15:32.423Z"}, {"lat": "44.130044", "lng": "9.695139", "elevation": "242.1999969482422", "time": "2013-09-20T12:15:33.383Z"}, {"lat": "44.130013", "lng": "9.695249", "elevation": "244.10000610351563", "time": "2013-09-20T12:15:44.327Z"}, {"lat": "44.130008", "lng": "9.69526", "elevation": "243.39999389648438", "time": "2013-09-20T12:15:45.378Z"}, {"lat": "44.129972", "lng": "9.695373", "elevation": "240.89999389648438", "time": "2013-09-20T12:15:53.316Z"}, {"lat": "44.129971", "lng": "9.695387", "elevation": "241.10000610351563", "time": "2013-09-20T12:15:54.306Z"}, {"lat": "44.129946", "lng": "9.695495", "elevation": "239.5", "time": "2013-09-20T12:16:00.317Z"}, {"lat": "44.129944", "lng": "9.695514", "elevation": "239.89999389648438", "time": "2013-09-20T12:16:01.319Z"}, {"lat": "44.129932", "lng": "9.695626", "elevation": "241.89999389648438", "time": "2013-09-20T12:16:08.311Z"}, {"lat": "44.129931", "lng": "9.695641", "elevation": "241.1999969482422", "time": "2013-09-20T12:16:09.307Z"}, {"lat": "44.129948", "lng": "9.695759", "elevation": "239.89999389648438", "time": "2013-09-20T12:16:18.411Z"}, {"lat": "44.129943", "lng": "9.69577", "elevation": "239.60000610351563", "time": "2013-09-20T12:16:19.441Z"}, {"lat": "44.129886", "lng": "9.695858", "elevation": "240.60000610351563", "time": "2013-09-20T12:16:27.455Z"}, {"lat": "44.129879", "lng": "9.695862", "elevation": "240.6999969482422", "time": "2013-09-20T12:16:28.430Z"}, {"lat": "44.129859", "lng": "9.69586", "elevation": "241.3000030517578", "time": "2013-09-20T12:16:34.437Z"}, {"lat": "44.129859", "lng": "9.695862", "elevation": "241.10000610351563", "time": "2013-09-20T12:16:35.468Z"}, {"lat": "44.129857", "lng": "9.695866", "elevation": "240.8000030517578", "time": "2013-09-20T12:16:37.404Z"}, {"lat": "44.129856", "lng": "9.695873", "elevation": "241.10000610351563", "time": "2013-09-20T12:16:38.370Z"}, {"lat": "44.12983", "lng": "9.695987", "elevation": "241.10000610351563", "time": "2013-09-20T12:16:47.307Z"}, {"lat": "44.129824", "lng": "9.696002", "elevation": "240.60000610351563", "time": "2013-09-20T12:16:48.301Z"}, {"lat": "44.129766", "lng": "9.696096", "elevation": "240.89999389648438", "time": "2013-09-20T12:16:56.316Z"}, {"lat": "44.129759", "lng": "9.696104", "elevation": "241.3000030517578", "time": "2013-09-20T12:16:57.311Z"}, {"lat": "44.129704", "lng": "9.696183", "elevation": "244.5", "time": "2013-09-20T12:17:06.415Z"}, {"lat": "44.129696", "lng": "9.696194", "elevation": "245.3000030517578", "time": "2013-09-20T12:17:07.464Z"}, {"lat": "44.129652", "lng": "9.6963", "elevation": "244.3000030517578", "time": "2013-09-20T12:17:14.400Z"}, {"lat": "44.129646", "lng": "9.696318", "elevation": "244.10000610351563", "time": "2013-09-20T12:17:15.472Z"}, {"lat": "44.129623", "lng": "9.696427", "elevation": "242.89999389648438", "time": "2013-09-20T12:17:22.314Z"}, {"lat": "44.12962", "lng": "9.696438", "elevation": "242.6999969482422", "time": "2013-09-20T12:17:23.344Z"}, {"lat": "44.129613", "lng": "9.696561", "elevation": "243.0", "time": "2013-09-20T12:17:33.319Z"}, {"lat": "44.129611", "lng": "9.696573", "elevation": "241.6999969482422", "time": "2013-09-20T12:17:34.316Z"}, {"lat": "44.129587", "lng": "9.696684", "elevation": "239.3000030517578", "time": "2013-09-20T12:17:42.359Z"}, {"lat": "44.129582", "lng": "9.696701", "elevation": "241.8000030517578", "time": "2013-09-20T12:17:43.346Z"}, {"lat": "44.129531", "lng": "9.696803", "elevation": "243.0", "time": "2013-09-20T12:17:49.396Z"}, {"lat": "44.129522", "lng": "9.696815", "elevation": "242.8000030517578", "time": "2013-09-20T12:17:50.363Z"}, {"lat": "44.12949", "lng": "9.696912", "elevation": "238.10000610351563", "time": "2013-09-20T12:17:57.345Z"}, {"lat": "44.129493", "lng": "9.696939", "elevation": "238.8000030517578", "time": "2013-09-20T12:17:58.320Z"}, {"lat": "44.129491", "lng": "9.697058", "elevation": "238.60000610351563", "time": "2013-09-20T12:18:03.318Z"}, {"lat": "44.129485", "lng": "9.697074", "elevation": "238.5", "time": "2013-09-20T12:18:04.317Z"}, {"lat": "44.129466", "lng": "9.697191", "elevation": "237.89999389648438", "time": "2013-09-20T12:18:15.317Z"}, {"lat": "44.129465", "lng": "9.697197", "elevation": "237.8000030517578", "time": "2013-09-20T12:18:16.318Z"}, {"lat": "44.129422", "lng": "9.697305", "elevation": "241.5", "time": "2013-09-20T12:18:24.319Z"}, {"lat": "44.129417", "lng": "9.697319", "elevation": "242.0", "time": "2013-09-20T12:18:25.318Z"}, {"lat": "44.129413", "lng": "9.697439", "elevation": "241.39999389648438", "time": "2013-09-20T12:18:34.320Z"}, {"lat": "44.129413", "lng": "9.697456", "elevation": "240.5", "time": "2013-09-20T12:18:35.318Z"}, {"lat": "44.129429", "lng": "9.697569", "elevation": "241.5", "time": "2013-09-20T12:18:43.485Z"}, {"lat": "44.12943", "lng": "9.697582", "elevation": "241.6999969482422", "time": "2013-09-20T12:18:44.328Z"}, {"lat": "44.129449", "lng": "9.697693", "elevation": "246.1999969482422", "time": "2013-09-20T12:18:51.343Z"}, {"lat": "44.129453", "lng": "9.697706", "elevation": "246.5", "time": "2013-09-20T12:18:52.324Z"}, {"lat": "44.129456", "lng": "9.697718", "elevation": "245.39999389648438", "time": "2013-09-20T12:18:56.432Z"}, {"lat": "44.129455", "lng": "9.697716", "elevation": "246.0", "time": "2013-09-20T12:18:57.403Z"}, {"lat": "44.129455", "lng": "9.697715", "elevation": "244.89999389648438", "time": "2013-09-20T12:19:34.330Z"}, {"lat": "44.12946", "lng": "9.697717", "elevation": "245.1999969482422", "time": "2013-09-20T12:19:35.323Z"}, {"lat": "44.129524", "lng": "9.697802", "elevation": "247.0", "time": "2013-09-20T12:19:49.325Z"}, {"lat": "44.129527", "lng": "9.697805", "elevation": "246.8000030517578", "time": "2013-09-20T12:19:50.325Z"}, {"lat": "44.129549", "lng": "9.697924", "elevation": "242.3000030517578", "time": "2013-09-20T12:19:58.338Z"}, {"lat": "44.129552", "lng": "9.697946", "elevation": "242.89999389648438", "time": "2013-09-20T12:19:59.326Z"}, {"lat": "44.129515", "lng": "9.698055", "elevation": "246.89999389648438", "time": "2013-09-20T12:20:06.398Z"}, {"lat": "44.129511", "lng": "9.698068", "elevation": "246.1999969482422", "time": "2013-09-20T12:20:07.425Z"}, {"lat": "44.129494", "lng": "9.698177", "elevation": "246.8000030517578", "time": "2013-09-20T12:20:14.370Z"}, {"lat": "44.12949", "lng": "9.698193", "elevation": "247.10000610351563", "time": "2013-09-20T12:20:15.431Z"}, {"lat": "44.129447", "lng": "9.698291", "elevation": "247.60000610351563", "time": "2013-09-20T12:20:22.367Z"}, {"lat": "44.129441", "lng": "9.698306", "elevation": "247.10000610351563", "time": "2013-09-20T12:20:23.420Z"}, {"lat": "44.12944", "lng": "9.698421", "elevation": "246.39999389648438", "time": "2013-09-20T12:20:32.440Z"}, {"lat": "44.129439", "lng": "9.698433", "elevation": "246.1999969482422", "time": "2013-09-20T12:20:33.453Z"}, {"lat": "44.129409", "lng": "9.698538", "elevation": "245.8000030517578", "time": "2013-09-20T12:20:40.449Z"}, {"lat": "44.129406", "lng": "9.698551", "elevation": "245.5", "time": "2013-09-20T12:20:41.411Z"}, {"lat": "44.129428", "lng": "9.698656", "elevation": "243.8000030517578", "time": "2013-09-20T12:21:03.330Z"}, {"lat": "44.129424", "lng": "9.698658", "elevation": "244.60000610351563", "time": "2013-09-20T12:21:04.335Z"}, {"lat": "44.129419", "lng": "9.698661", "elevation": "244.6999969482422", "time": "2013-09-20T12:21:05.334Z"}, {"lat": "44.129416", "lng": "9.698663", "elevation": "244.60000610351563", "time": "2013-09-20T12:21:06.334Z"}, {"lat": "44.129411", "lng": "9.698665", "elevation": "244.60000610351563", "time": "2013-09-20T12:21:08.368Z"}, {"lat": "44.12941", "lng": "9.698666", "elevation": "244.60000610351563", "time": "2013-09-20T12:21:09.331Z"}, {"lat": "44.129423", "lng": "9.698705", "elevation": "242.5", "time": "2013-09-20T12:21:36.334Z"}, {"lat": "44.129429", "lng": "9.698716", "elevation": "244.60000610351563", "time": "2013-09-20T12:21:37.334Z"}, {"lat": "44.12947", "lng": "9.698803", "elevation": "247.8000030517578", "time": "2013-09-20T12:21:41.350Z"}, {"lat": "44.129479", "lng": "9.698838", "elevation": "250.10000610351563", "time": "2013-09-20T12:21:42.377Z"}, {"lat": "44.129478", "lng": "9.698962", "elevation": "255.1999969482422", "time": "2013-09-20T12:21:47.462Z"}, {"lat": "44.129475", "lng": "9.698981", "elevation": "255.0", "time": "2013-09-20T12:21:48.471Z"}, {"lat": "44.129489", "lng": "9.6991", "elevation": "257.5", "time": "2013-09-20T12:21:55.461Z"}, {"lat": "44.129487", "lng": "9.699113", "elevation": "258.70001220703125", "time": "2013-09-20T12:21:56.350Z"}, {"lat": "44.129481", "lng": "9.699237", "elevation": "261.79998779296875", "time": "2013-09-20T12:22:06.390Z"}, {"lat": "44.129483", "lng": "9.699249", "elevation": "262.1000061035156", "time": "2013-09-20T12:22:07.378Z"}, {"lat": "44.129483", "lng": "9.69937", "elevation": "266.3999938964844", "time": "2013-09-20T12:22:16.346Z"}, {"lat": "44.129483", "lng": "9.699384", "elevation": "266.0", "time": "2013-09-20T12:22:17.341Z"}, {"lat": "44.129476", "lng": "9.699499", "elevation": "265.20001220703125", "time": "2013-09-20T12:22:26.354Z"}, {"lat": "44.129476", "lng": "9.699511", "elevation": "265.20001220703125", "time": "2013-09-20T12:22:27.362Z"}, {"lat": "44.129482", "lng": "9.699628", "elevation": "266.5", "time": "2013-09-20T12:22:35.343Z"}, {"lat": "44.129483", "lng": "9.699644", "elevation": "266.3999938964844", "time": "2013-09-20T12:22:36.344Z"}, {"lat": "44.129467", "lng": "9.69976", "elevation": "267.5", "time": "2013-09-20T12:22:49.347Z"}, {"lat": "44.129468", "lng": "9.699768", "elevation": "267.3999938964844", "time": "2013-09-20T12:22:50.393Z"}, {"lat": "44.129434", "lng": "9.699871", "elevation": "272.70001220703125", "time": "2013-09-20T12:23:01.424Z"}, {"lat": "44.129423", "lng": "9.699888", "elevation": "272.5", "time": "2013-09-20T12:23:02.388Z"}, {"lat": "44.129365", "lng": "9.699975", "elevation": "271.79998779296875", "time": "2013-09-20T12:23:08.350Z"}, {"lat": "44.12936", "lng": "9.699988", "elevation": "271.29998779296875", "time": "2013-09-20T12:23:09.347Z"}, {"lat": "44.12933", "lng": "9.700052", "elevation": "271.79998779296875", "time": "2013-09-20T12:23:20.350Z"}, {"lat": "44.12933", "lng": "9.700053", "elevation": "271.5", "time": "2013-09-20T12:23:21.346Z"}, {"lat": "44.129329", "lng": "9.700055", "elevation": "271.5", "time": "2013-09-20T12:23:22.414Z"}, {"lat": "44.129327", "lng": "9.700057", "elevation": "270.6000061035156", "time": "2013-09-20T12:23:23.346Z"}, {"lat": "44.129278", "lng": "9.700151", "elevation": "268.0", "time": "2013-09-20T12:23:32.453Z"}, {"lat": "44.129272", "lng": "9.70017", "elevation": "268.1000061035156", "time": "2013-09-20T12:23:33.429Z"}, {"lat": "44.129243", "lng": "9.700282", "elevation": "267.20001220703125", "time": "2013-09-20T12:23:39.480Z"}, {"lat": "44.129236", "lng": "9.700293", "elevation": "267.5", "time": "2013-09-20T12:23:40.440Z"}, {"lat": "44.129218", "lng": "9.700301", "elevation": "267.1000061035156", "time": "2013-09-20T12:23:46.423Z"}, {"lat": "44.129219", "lng": "9.700299", "elevation": "267.1000061035156", "time": "2013-09-20T12:23:47.492Z"}, {"lat": "44.129224", "lng": "9.700306", "elevation": "267.0", "time": "2013-09-20T12:23:51.366Z"}, {"lat": "44.129224", "lng": "9.700313", "elevation": "268.1000061035156", "time": "2013-09-20T12:23:52.360Z"}, {"lat": "44.129148", "lng": "9.70038", "elevation": "271.8999938964844", "time": "2013-09-20T12:24:00.359Z"}, {"lat": "44.129135", "lng": "9.700388", "elevation": "271.8999938964844", "time": "2013-09-20T12:24:01.357Z"}, {"lat": "44.129087", "lng": "9.700477", "elevation": "271.1000061035156", "time": "2013-09-20T12:24:08.351Z"}, {"lat": "44.12908", "lng": "9.700491", "elevation": "270.29998779296875", "time": "2013-09-20T12:24:09.370Z"}, {"lat": "44.129045", "lng": "9.700595", "elevation": "265.5", "time": "2013-09-20T12:24:17.351Z"}, {"lat": "44.129041", "lng": "9.70061", "elevation": "265.70001220703125", "time": "2013-09-20T12:24:18.484Z"}, {"lat": "44.129019", "lng": "9.700718", "elevation": "265.3999938964844", "time": "2013-09-20T12:24:25.357Z"}, {"lat": "44.129018", "lng": "9.700733", "elevation": "265.0", "time": "2013-09-20T12:24:26.436Z"}, {"lat": "44.128987", "lng": "9.700839", "elevation": "261.3999938964844", "time": "2013-09-20T12:24:34.489Z"}, {"lat": "44.128987", "lng": "9.700854", "elevation": "259.6000061035156", "time": "2013-09-20T12:24:35.475Z"}, {"lat": "44.128987", "lng": "9.700972", "elevation": "257.20001220703125", "time": "2013-09-20T12:24:43.506Z"}, {"lat": "44.128989", "lng": "9.700981", "elevation": "256.29998779296875", "time": "2013-09-20T12:24:44.354Z"}, {"lat": "44.128958", "lng": "9.701041", "elevation": "256.20001220703125", "time": "2013-09-20T12:25:03.298Z"}, {"lat": "44.128956", "lng": "9.701041", "elevation": "256.5", "time": "2013-09-20T12:25:03.369Z"}, {"lat": "44.128952", "lng": "9.70104", "elevation": "256.1000061035156", "time": "2013-09-20T12:25:04.359Z"}, {"lat": "44.128947", "lng": "9.701038", "elevation": "256.0", "time": "2013-09-20T12:25:05.360Z"}, {"lat": "44.128921", "lng": "9.701043", "elevation": "256.5", "time": "2013-09-20T12:25:11.363Z"}, {"lat": "44.128922", "lng": "9.701045", "elevation": "256.3999938964844", "time": "2013-09-20T12:25:12.357Z"}, {"lat": "44.128919", "lng": "9.701067", "elevation": "257.70001220703125", "time": "2013-09-20T12:25:46.355Z"}, {"lat": "44.128915", "lng": "9.701071", "elevation": "257.3999938964844", "time": "2013-09-20T12:25:47.359Z"}, {"lat": "44.128904", "lng": "9.701189", "elevation": "244.39999389648438", "time": "2013-09-20T12:26:03.357Z"}, {"lat": "44.128906", "lng": "9.701205", "elevation": "245.39999389648438", "time": "2013-09-20T12:26:04.361Z"}, {"lat": "44.128893", "lng": "9.701294", "elevation": "245.1999969482422", "time": "2013-09-20T12:26:13.437Z"}, {"lat": "44.128893", "lng": "9.701293", "elevation": "244.1999969482422", "time": "2013-09-20T12:26:14.473Z"}, {"lat": "44.128885", "lng": "9.701297", "elevation": "245.1999969482422", "time": "2013-09-20T12:26:26.363Z"}, {"lat": "44.128886", "lng": "9.701302", "elevation": "245.10000610351563", "time": "2013-09-20T12:26:27.362Z"}, {"lat": "44.128906", "lng": "9.701423", "elevation": "246.10000610351563", "time": "2013-09-20T12:26:42.371Z"}, {"lat": "44.128906", "lng": "9.701446", "elevation": "246.6999969482422", "time": "2013-09-20T12:26:43.362Z"}, {"lat": "44.128899", "lng": "9.701556", "elevation": "247.10000610351563", "time": "2013-09-20T12:26:48.363Z"}, {"lat": "44.128897", "lng": "9.701573", "elevation": "247.0", "time": "2013-09-20T12:26:49.367Z"}, {"lat": "44.128871", "lng": "9.701631", "elevation": "246.5", "time": "2013-09-20T12:26:59.367Z"}, {"lat": "44.128872", "lng": "9.701631", "elevation": "246.5", "time": "2013-09-20T12:27:00.366Z"}, {"lat": "44.128875", "lng": "9.701643", "elevation": "244.5", "time": "2013-09-20T12:28:08.370Z"}, {"lat": "44.128877", "lng": "9.70165", "elevation": "244.39999389648438", "time": "2013-09-20T12:28:09.380Z"}, {"lat": "44.12887", "lng": "9.701716", "elevation": "246.39999389648438", "time": "2013-09-20T12:28:23.361Z"}, {"lat": "44.12887", "lng": "9.701716", "elevation": "246.39999389648438", "time": "2013-09-20T12:28:23.393Z"}, {"lat": "44.128873", "lng": "9.701713", "elevation": "246.10000610351563", "time": "2013-09-20T12:28:52.380Z"}, {"lat": "44.128876", "lng": "9.70172", "elevation": "245.5", "time": "2013-09-20T12:28:53.441Z"}, {"lat": "44.128935", "lng": "9.701809", "elevation": "245.5", "time": "2013-09-20T12:28:59.379Z"}, {"lat": "44.128945", "lng": "9.701817", "elevation": "245.1999969482422", "time": "2013-09-20T12:29:00.380Z"}, {"lat": "44.129022", "lng": "9.701861", "elevation": "239.5", "time": "2013-09-20T12:29:09.381Z"}, {"lat": "44.129029", "lng": "9.701876", "elevation": "239.6999969482422", "time": "2013-09-20T12:29:10.387Z"}, {"lat": "44.129091", "lng": "9.701959", "elevation": "237.6999969482422", "time": "2013-09-20T12:29:19.455Z"}, {"lat": "44.129097", "lng": "9.701968", "elevation": "238.1999969482422", "time": "2013-09-20T12:29:20.479Z"}, {"lat": "44.129162", "lng": "9.702031", "elevation": "237.6999969482422", "time": "2013-09-20T12:29:29.432Z"}, {"lat": "44.129172", "lng": "9.702037", "elevation": "238.3000030517578", "time": "2013-09-20T12:29:30.416Z"}, {"lat": "44.129235", "lng": "9.702101", "elevation": "239.0", "time": "2013-09-20T12:29:36.433Z"}, {"lat": "44.129245", "lng": "9.702115", "elevation": "239.10000610351563", "time": "2013-09-20T12:29:37.451Z"}, {"lat": "44.129271", "lng": "9.702144", "elevation": "237.0", "time": "2013-09-20T12:29:43.470Z"}, {"lat": "44.129271", "lng": "9.70214", "elevation": "236.6999969482422", "time": "2013-09-20T12:29:44.482Z"}, {"lat": "44.129273", "lng": "9.70215", "elevation": "238.3000030517578", "time": "2013-09-20T12:31:03.379Z"}, {"lat": "44.129277", "lng": "9.702157", "elevation": "238.60000610351563", "time": "2013-09-20T12:31:04.389Z"}, {"lat": "44.129349", "lng": "9.702223", "elevation": "241.5", "time": "2013-09-20T12:31:13.393Z"}, {"lat": "44.129357", "lng": "9.702229", "elevation": "242.0", "time": "2013-09-20T12:31:14.389Z"}, {"lat": "44.129421", "lng": "9.7023", "elevation": "239.39999389648438", "time": "2013-09-20T12:31:21.384Z"}, {"lat": "44.129429", "lng": "9.702318", "elevation": "239.3000030517578", "time": "2013-09-20T12:31:22.388Z"}, {"lat": "44.129476", "lng": "9.702409", "elevation": "239.60000610351563", "time": "2013-09-20T12:31:26.384Z"}, {"lat": "44.129483", "lng": "9.70242", "elevation": "239.60000610351563", "time": "2013-09-20T12:31:27.386Z"}, {"lat": "44.129499", "lng": "9.702465", "elevation": "240.1999969482422", "time": "2013-09-20T12:31:37.386Z"}, {"lat": "44.129499", "lng": "9.702466", "elevation": "240.1999969482422", "time": "2013-09-20T12:31:38.430Z"}, {"lat": "44.129499", "lng": "9.702472", "elevation": "240.10000610351563", "time": "2013-09-20T12:31:44.390Z"}, {"lat": "44.1295", "lng": "9.702479", "elevation": "239.89999389648438", "time": "2013-09-20T12:31:45.392Z"}, {"lat": "44.129526", "lng": "9.702587", "elevation": "241.39999389648438", "time": "2013-09-20T12:31:58.392Z"}, {"lat": "44.129521", "lng": "9.7026", "elevation": "242.39999389648438", "time": "2013-09-20T12:31:59.517Z"}, {"lat": "44.129451", "lng": "9.70267", "elevation": "240.3000030517578", "time": "2013-09-20T12:32:11.391Z"}, {"lat": "44.129454", "lng": "9.702671", "elevation": "240.3000030517578", "time": "2013-09-20T12:32:12.394Z"}, {"lat": "44.129455", "lng": "9.702676", "elevation": "240.1999969482422", "time": "2013-09-20T12:32:16.399Z"}, {"lat": "44.129451", "lng": "9.702682", "elevation": "240.6999969482422", "time": "2013-09-20T12:32:17.395Z"}, {"lat": "44.129404", "lng": "9.702783", "elevation": "236.1999969482422", "time": "2013-09-20T12:32:28.460Z"}, {"lat": "44.1294", "lng": "9.702801", "elevation": "236.0", "time": "2013-09-20T12:32:29.594Z"}, {"lat": "44.129382", "lng": "9.702908", "elevation": "232.8000030517578", "time": "2013-09-20T12:32:40.557Z"}, {"lat": "44.129379", "lng": "9.702926", "elevation": "232.5", "time": "2013-09-20T12:32:41.438Z"}, {"lat": "44.129306", "lng": "9.703", "elevation": "236.0", "time": "2013-09-20T12:32:50.393Z"}, {"lat": "44.129296", "lng": "9.703005", "elevation": "235.89999389648438", "time": "2013-09-20T12:32:51.415Z"}, {"lat": "44.129223", "lng": "9.703072", "elevation": "233.3000030517578", "time": "2013-09-20T12:33:03.393Z"}, {"lat": "44.12922", "lng": "9.703076", "elevation": "233.3000030517578", "time": "2013-09-20T12:33:04.400Z"}, {"lat": "44.129218", "lng": "9.703082", "elevation": "232.8000030517578", "time": "2013-09-20T12:33:06.397Z"}, {"lat": "44.129217", "lng": "9.703084", "elevation": "232.6999969482422", "time": "2013-09-20T12:33:07.402Z"}, {"lat": "44.129212", "lng": "9.703099", "elevation": "232.39999389648438", "time": "2013-09-20T12:33:16.395Z"}, {"lat": "44.129208", "lng": "9.703101", "elevation": "232.1999969482422", "time": "2013-09-20T12:33:17.395Z"}, {"lat": "44.129155", "lng": "9.703195", "elevation": "229.8000030517578", "time": "2013-09-20T12:33:33.559Z"}, {"lat": "44.12915", "lng": "9.703203", "elevation": "229.3000030517578", "time": "2013-09-20T12:33:34.403Z"}, {"lat": "44.129095", "lng": "9.703298", "elevation": "224.39999389648438", "time": "2013-09-20T12:33:51.438Z"}, {"lat": "44.129092", "lng": "9.703302", "elevation": "224.5", "time": "2013-09-20T12:33:52.443Z"}, {"lat": "44.129028", "lng": "9.703389", "elevation": "223.60000610351563", "time": "2013-09-20T12:34:06.408Z"}, {"lat": "44.129018", "lng": "9.703398", "elevation": "223.6999969482422", "time": "2013-09-20T12:34:07.557Z"}, {"lat": "44.128966", "lng": "9.703497", "elevation": "219.0", "time": "2013-09-20T12:34:16.567Z"}, {"lat": "44.128962", "lng": "9.703506", "elevation": "218.39999389648438", "time": "2013-09-20T12:34:17.597Z"}, {"lat": "44.128888", "lng": "9.703562", "elevation": "214.39999389648438", "time": "2013-09-20T12:34:30.522Z"}, {"lat": "44.128883", "lng": "9.703575", "elevation": "214.10000610351563", "time": "2013-09-20T12:34:31.407Z"}, {"lat": "44.12883", "lng": "9.703668", "elevation": "213.10000610351563", "time": "2013-09-20T12:34:45.391Z"}, {"lat": "44.128823", "lng": "9.703683", "elevation": "213.0", "time": "2013-09-20T12:34:46.401Z"}, {"lat": "44.12877", "lng": "9.703782", "elevation": "212.60000610351563", "time": "2013-09-20T12:34:53.404Z"}, {"lat": "44.128767", "lng": "9.703785", "elevation": "212.5", "time": "2013-09-20T12:34:54.406Z"}, {"lat": "44.128728", "lng": "9.703793", "elevation": "212.3000030517578", "time": "2013-09-20T12:35:06.404Z"}, {"lat": "44.128728", "lng": "9.703795", "elevation": "212.3000030517578", "time": "2013-09-20T12:35:07.401Z"}, {"lat": "44.128729", "lng": "9.703799", "elevation": "212.1999969482422", "time": "2013-09-20T12:35:09.405Z"}, {"lat": "44.128728", "lng": "9.703805", "elevation": "211.10000610351563", "time": "2013-09-20T12:35:10.419Z"}, {"lat": "44.128703", "lng": "9.703918", "elevation": "208.3000030517578", "time": "2013-09-20T12:35:16.403Z"}, {"lat": "44.128695", "lng": "9.703941", "elevation": "209.60000610351563", "time": "2013-09-20T12:35:17.401Z"}, {"lat": "44.128657", "lng": "9.704026", "elevation": "209.0", "time": "2013-09-20T12:35:21.408Z"}, {"lat": "44.12865", "lng": "9.704052", "elevation": "208.1999969482422", "time": "2013-09-20T12:35:22.403Z"}, {"lat": "44.128642", "lng": "9.704164", "elevation": "204.89999389648438", "time": "2013-09-20T12:35:26.403Z"}, {"lat": "44.128642", "lng": "9.704191", "elevation": "203.8000030517578", "time": "2013-09-20T12:35:27.403Z"}, {"lat": "44.128601", "lng": "9.704301", "elevation": "204.60000610351563", "time": "2013-09-20T12:35:34.404Z"}, {"lat": "44.128592", "lng": "9.704309", "elevation": "204.60000610351563", "time": "2013-09-20T12:35:35.403Z"}, {"lat": "44.128533", "lng": "9.70439", "elevation": "202.10000610351563", "time": "2013-09-20T12:35:44.407Z"}, {"lat": "44.128522", "lng": "9.704393", "elevation": "202.3000030517578", "time": "2013-09-20T12:35:45.405Z"}, {"lat": "44.128457", "lng": "9.704467", "elevation": "202.1999969482422", "time": "2013-09-20T12:35:53.407Z"}, {"lat": "44.128454", "lng": "9.704479", "elevation": "202.10000610351563", "time": "2013-09-20T12:35:54.411Z"}, {"lat": "44.128382", "lng": "9.704547", "elevation": "199.8000030517578", "time": "2013-09-20T12:36:08.418Z"}, {"lat": "44.128374", "lng": "9.704549", "elevation": "199.0", "time": "2013-09-20T12:36:09.422Z"}, {"lat": "44.128295", "lng": "9.704591", "elevation": "203.3000030517578", "time": "2013-09-20T12:36:21.456Z"}, {"lat": "44.128287", "lng": "9.704589", "elevation": "203.10000610351563", "time": "2013-09-20T12:36:22.404Z"}, {"lat": "44.128277", "lng": "9.704572", "elevation": "204.5", "time": "2013-09-20T12:36:27.458Z"}, {"lat": "44.12828", "lng": "9.704571", "elevation": "204.10000610351563", "time": "2013-09-20T12:36:28.415Z"}, {"lat": "44.128278", "lng": "9.704576", "elevation": "203.8000030517578", "time": "2013-09-20T12:36:48.450Z"}, {"lat": "44.128273", "lng": "9.704577", "elevation": "203.6999969482422", "time": "2013-09-20T12:36:49.413Z"}, {"lat": "44.128198", "lng": "9.704595", "elevation": "201.39999389648438", "time": "2013-09-20T12:36:53.502Z"}, {"lat": "44.128176", "lng": "9.704605", "elevation": "201.0", "time": "2013-09-20T12:36:54.428Z"}, {"lat": "44.128098", "lng": "9.704642", "elevation": "201.10000610351563", "time": "2013-09-20T12:36:58.439Z"}, {"lat": "44.128086", "lng": "9.704649", "elevation": "200.60000610351563", "time": "2013-09-20T12:36:59.433Z"}, {"lat": "44.128024", "lng": "9.704725", "elevation": "201.0", "time": "2013-09-20T12:37:07.421Z"}, {"lat": "44.128015", "lng": "9.704735", "elevation": "200.3000030517578", "time": "2013-09-20T12:37:08.410Z"}, {"lat": "44.127939", "lng": "9.704802", "elevation": "201.5", "time": "2013-09-20T12:37:16.415Z"}, {"lat": "44.127932", "lng": "9.704812", "elevation": "200.39999389648438", "time": "2013-09-20T12:37:17.413Z"}, {"lat": "44.127851", "lng": "9.704862", "elevation": "199.60000610351563", "time": "2013-09-20T12:37:25.411Z"}, {"lat": "44.127842", "lng": "9.704868", "elevation": "198.0", "time": "2013-09-20T12:37:26.412Z"}, {"lat": "44.127764", "lng": "9.704929", "elevation": "196.89999389648438", "time": "2013-09-20T12:37:35.437Z"}, {"lat": "44.127755", "lng": "9.704934", "elevation": "196.60000610351563", "time": "2013-09-20T12:37:36.412Z"}, {"lat": "44.127692", "lng": "9.70502", "elevation": "195.60000610351563", "time": "2013-09-20T12:37:50.413Z"}, {"lat": "44.127682", "lng": "9.705018", "elevation": "196.0", "time": "2013-09-20T12:37:51.418Z"}, {"lat": "44.12761", "lng": "9.705085", "elevation": "197.8000030517578", "time": "2013-09-20T12:38:00.457Z"}, {"lat": "44.127601", "lng": "9.705095", "elevation": "198.10000610351563", "time": "2013-09-20T12:38:01.416Z"}, {"lat": "44.127524", "lng": "9.70515", "elevation": "201.1999969482422", "time": "2013-09-20T12:38:08.421Z"}, {"lat": "44.127507", "lng": "9.705155", "elevation": "201.60000610351563", "time": "2013-09-20T12:38:09.423Z"}, {"lat": "44.127428", "lng": "9.705203", "elevation": "199.8000030517578", "time": "2013-09-20T12:38:16.418Z"}, {"lat": "44.127425", "lng": "9.705221", "elevation": "200.5", "time": "2013-09-20T12:38:17.427Z"}, {"lat": "44.127347", "lng": "9.705267", "elevation": "200.10000610351563", "time": "2013-09-20T12:38:26.413Z"}, {"lat": "44.127337", "lng": "9.705264", "elevation": "199.8000030517578", "time": "2013-09-20T12:38:27.419Z"}, {"lat": "44.127269", "lng": "9.705196", "elevation": "199.0", "time": "2013-09-20T12:38:35.418Z"}, {"lat": "44.12726", "lng": "9.705196", "elevation": "198.8000030517578", "time": "2013-09-20T12:38:36.417Z"}, {"lat": "44.127177", "lng": "9.705226", "elevation": "198.6999969482422", "time": "2013-09-20T12:38:44.433Z"}, {"lat": "44.127162", "lng": "9.70522", "elevation": "199.1999969482422", "time": "2013-09-20T12:38:45.429Z"}, {"lat": "44.127075", "lng": "9.705187", "elevation": "201.60000610351563", "time": "2013-09-20T12:38:54.421Z"}, {"lat": "44.127073", "lng": "9.705186", "elevation": "200.6999969482422", "time": "2013-09-20T12:38:55.425Z"}, {"lat": "44.127074", "lng": "9.705191", "elevation": "202.39999389648438", "time": "2013-09-20T12:38:57.451Z"}, {"lat": "44.127075", "lng": "9.705194", "elevation": "202.6999969482422", "time": "2013-09-20T12:38:58.448Z"}, {"lat": "44.127073", "lng": "9.705195", "elevation": "202.6999969482422", "time": "2013-09-20T12:38:59.424Z"}, {"lat": "44.127069", "lng": "9.705196", "elevation": "202.39999389648438", "time": "2013-09-20T12:39:00.447Z"}, {"lat": "44.126983", "lng": "9.705228", "elevation": "200.39999389648438", "time": "2013-09-20T12:39:07.436Z"}, {"lat": "44.126973", "lng": "9.705236", "elevation": "199.89999389648438", "time": "2013-09-20T12:39:08.452Z"}, {"lat": "44.126891", "lng": "9.705271", "elevation": "200.8000030517578", "time": "2013-09-20T12:39:16.420Z"}, {"lat": "44.12688", "lng": "9.705274", "elevation": "201.39999389648438", "time": "2013-09-20T12:39:17.426Z"}, {"lat": "44.126794", "lng": "9.705289", "elevation": "201.8000030517578", "time": "2013-09-20T12:39:25.422Z"}, {"lat": "44.126784", "lng": "9.705294", "elevation": "203.5", "time": "2013-09-20T12:39:26.435Z"}, {"lat": "44.126701", "lng": "9.705321", "elevation": "204.1999969482422", "time": "2013-09-20T12:39:34.434Z"}, {"lat": "44.126692", "lng": "9.705322", "elevation": "203.3000030517578", "time": "2013-09-20T12:39:35.415Z"}, {"lat": "44.126611", "lng": "9.705346", "elevation": "204.39999389648438", "time": "2013-09-20T12:39:47.423Z"}, {"lat": "44.1266", "lng": "9.705351", "elevation": "203.8000030517578", "time": "2013-09-20T12:39:48.421Z"}, {"lat": "44.12651", "lng": "9.705339", "elevation": "204.5", "time": "2013-09-20T12:39:56.426Z"}, {"lat": "44.126498", "lng": "9.705339", "elevation": "204.89999389648438", "time": "2013-09-20T12:39:57.423Z"}, {"lat": "44.126414", "lng": "9.705331", "elevation": "203.60000610351563", "time": "2013-09-20T12:40:06.428Z"}, {"lat": "44.126406", "lng": "9.705328", "elevation": "204.5", "time": "2013-09-20T12:40:07.434Z"}, {"lat": "44.126321", "lng": "9.705322", "elevation": "205.1999969482422", "time": "2013-09-20T12:40:16.431Z"}, {"lat": "44.126312", "lng": "9.705322", "elevation": "205.39999389648438", "time": "2013-09-20T12:40:17.426Z"}, {"lat": "44.126223", "lng": "9.705316", "elevation": "205.5", "time": "2013-09-20T12:40:28.427Z"}, {"lat": "44.126218", "lng": "9.705313", "elevation": "205.3000030517578", "time": "2013-09-20T12:40:29.427Z"}, {"lat": "44.126131", "lng": "9.705326", "elevation": "205.39999389648438", "time": "2013-09-20T12:40:40.431Z"}, {"lat": "44.126122", "lng": "9.705322", "elevation": "205.1999969482422", "time": "2013-09-20T12:40:41.428Z"}, {"lat": "44.126033", "lng": "9.705315", "elevation": "207.89999389648438", "time": "2013-09-20T12:40:53.425Z"}, {"lat": "44.126028", "lng": "9.705317", "elevation": "209.0", "time": "2013-09-20T12:40:54.425Z"}, {"lat": "44.125964", "lng": "9.705384", "elevation": "205.60000610351563", "time": "2013-09-20T12:41:05.431Z"}, {"lat": "44.125953", "lng": "9.70539", "elevation": "205.39999389648438", "time": "2013-09-20T12:41:06.430Z"}, {"lat": "44.125871", "lng": "9.705406", "elevation": "206.8000030517578", "time": "2013-09-20T12:41:13.431Z"}, {"lat": "44.125863", "lng": "9.705412", "elevation": "207.60000610351563", "time": "2013-09-20T12:41:14.431Z"}, {"lat": "44.12584", "lng": "9.705447", "elevation": "209.60000610351563", "time": "2013-09-20T12:41:22.458Z"}, {"lat": "44.125839", "lng": "9.705442", "elevation": "209.6999969482422", "time": "2013-09-20T12:41:23.479Z"}, {"lat": "44.125834", "lng": "9.705434", "elevation": "209.6999969482422", "time": "2013-09-20T12:41:24.467Z"}, {"lat": "44.125754", "lng": "9.705474", "elevation": "210.0", "time": "2013-09-20T12:41:41.436Z"}, {"lat": "44.125746", "lng": "9.705478", "elevation": "209.60000610351563", "time": "2013-09-20T12:41:42.427Z"}, {"lat": "44.125667", "lng": "9.705535", "elevation": "210.89999389648438", "time": "2013-09-20T12:41:56.435Z"}, {"lat": "44.125661", "lng": "9.70553", "elevation": "211.10000610351563", "time": "2013-09-20T12:41:57.430Z"}, {"lat": "44.125642", "lng": "9.705512", "elevation": "211.1999969482422", "time": "2013-09-20T12:42:03.763Z"}, {"lat": "44.125642", "lng": "9.705512", "elevation": "211.10000610351563", "time": "2013-09-20T12:42:04.433Z"}, {"lat": "44.125641", "lng": "9.705517", "elevation": "210.10000610351563", "time": "2013-09-20T12:42:20.442Z"}, {"lat": "44.125637", "lng": "9.705523", "elevation": "209.3000030517578", "time": "2013-09-20T12:42:21.443Z"}, {"lat": "44.125573", "lng": "9.705609", "elevation": "208.6999969482422", "time": "2013-09-20T12:42:34.481Z"}, {"lat": "44.125564", "lng": "9.705608", "elevation": "208.5", "time": "2013-09-20T12:42:35.461Z"}, {"lat": "44.125502", "lng": "9.70569", "elevation": "204.10000610351563", "time": "2013-09-20T12:42:59.440Z"}, {"lat": "44.125494", "lng": "9.70569", "elevation": "205.3000030517578", "time": "2013-09-20T12:43:00.442Z"}, {"lat": "44.12542", "lng": "9.705738", "elevation": "203.89999389648438", "time": "2013-09-20T12:43:08.576Z"}, {"lat": "44.125415", "lng": "9.705751", "elevation": "204.60000610351563", "time": "2013-09-20T12:43:09.438Z"}, {"lat": "44.125409", "lng": "9.705799", "elevation": "203.1999969482422", "time": "2013-09-20T12:43:17.451Z"}, {"lat": "44.125409", "lng": "9.7058", "elevation": "203.1999969482422", "time": "2013-09-20T12:43:18.450Z"}, {"lat": "44.125401", "lng": "9.705805", "elevation": "202.6999969482422", "time": "2013-09-20T12:43:27.453Z"}, {"lat": "44.125398", "lng": "9.705807", "elevation": "203.0", "time": "2013-09-20T12:43:28.442Z"}, {"lat": "44.125308", "lng": "9.705818", "elevation": "200.39999389648438", "time": "2013-09-20T12:43:41.442Z"}, {"lat": "44.125303", "lng": "9.705818", "elevation": "200.39999389648438", "time": "2013-09-20T12:43:42.451Z"}, {"lat": "44.125296", "lng": "9.705823", "elevation": "201.1999969482422", "time": "2013-09-20T12:43:46.451Z"}, {"lat": "44.125297", "lng": "9.705825", "elevation": "200.89999389648438", "time": "2013-09-20T12:43:47.444Z"}, {"lat": "44.125301", "lng": "9.705845", "elevation": "200.8000030517578", "time": "2013-09-20T12:44:50.504Z"}, {"lat": "44.125303", "lng": "9.705852", "elevation": "200.6999969482422", "time": "2013-09-20T12:44:51.550Z"}, {"lat": "44.125306", "lng": "9.705857", "elevation": "200.1999969482422", "time": "2013-09-20T12:44:53.569Z"}, {"lat": "44.125306", "lng": "9.705857", "elevation": "200.1999969482422", "time": "2013-09-20T12:44:54.512Z"}, {"lat": "44.125297", "lng": "9.705855", "elevation": "200.10000610351563", "time": "2013-09-20T12:45:04.464Z"}, {"lat": "44.125293", "lng": "9.705857", "elevation": "200.60000610351563", "time": "2013-09-20T12:45:05.456Z"}, {"lat": "44.125211", "lng": "9.705871", "elevation": "200.5", "time": "2013-09-20T12:45:16.543Z"}, {"lat": "44.125203", "lng": "9.705875", "elevation": "200.1999969482422", "time": "2013-09-20T12:45:17.520Z"}, {"lat": "44.125137", "lng": "9.705898", "elevation": "198.8000030517578", "time": "2013-09-20T12:45:35.458Z"}, {"lat": "44.125138", "lng": "9.705901", "elevation": "198.89999389648438", "time": "2013-09-20T12:45:36.451Z"}, {"lat": "44.125132", "lng": "9.7059", "elevation": "198.8000030517578", "time": "2013-09-20T12:45:41.522Z"}, {"lat": "44.125126", "lng": "9.705904", "elevation": "198.39999389648438", "time": "2013-09-20T12:45:42.556Z"}, {"lat": "44.125051", "lng": "9.705964", "elevation": "196.3000030517578", "time": "2013-09-20T12:45:52.460Z"}, {"lat": "44.125046", "lng": "9.705967", "elevation": "195.89999389648438", "time": "2013-09-20T12:45:53.472Z"}, {"lat": "44.124957", "lng": "9.705985", "elevation": "193.5", "time": "2013-09-20T12:46:08.499Z"}, {"lat": "44.12495", "lng": "9.70599", "elevation": "193.0", "time": "2013-09-20T12:46:09.460Z"}, {"lat": "44.124887", "lng": "9.706078", "elevation": "191.10000610351563", "time": "2013-09-20T12:46:30.474Z"}, {"lat": "44.124885", "lng": "9.706087", "elevation": "190.8000030517578", "time": "2013-09-20T12:46:31.459Z"}, {"lat": "44.124875", "lng": "9.706202", "elevation": "187.1999969482422", "time": "2013-09-20T12:46:40.467Z"}, {"lat": "44.124873", "lng": "9.706214", "elevation": "186.3000030517578", "time": "2013-09-20T12:46:41.467Z"}, {"lat": "44.124862", "lng": "9.706334", "elevation": "182.1999969482422", "time": "2013-09-20T12:46:55.468Z"}, {"lat": "44.124861", "lng": "9.70634", "elevation": "181.8000030517578", "time": "2013-09-20T12:46:56.457Z"}, {"lat": "44.124781", "lng": "9.706388", "elevation": "180.60000610351563", "time": "2013-09-20T12:47:09.469Z"}, {"lat": "44.124774", "lng": "9.70639", "elevation": "180.5", "time": "2013-09-20T12:47:10.475Z"}, {"lat": "44.124711", "lng": "9.706452", "elevation": "181.0", "time": "2013-09-20T12:47:34.564Z"}, {"lat": "44.12471", "lng": "9.706451", "elevation": "181.39999389648438", "time": "2013-09-20T12:47:35.605Z"}, {"lat": "44.124705", "lng": "9.706454", "elevation": "181.3000030517578", "time": "2013-09-20T12:47:38.571Z"}, {"lat": "44.124702", "lng": "9.706456", "elevation": "181.1999969482422", "time": "2013-09-20T12:47:39.486Z"}, {"lat": "44.124628", "lng": "9.706508", "elevation": "178.3000030517578", "time": "2013-09-20T12:47:51.589Z"}, {"lat": "44.12462", "lng": "9.706511", "elevation": "178.3000030517578", "time": "2013-09-20T12:47:52.581Z"}, {"lat": "44.124535", "lng": "9.706541", "elevation": "178.0", "time": "2013-09-20T12:48:02.461Z"}, {"lat": "44.124525", "lng": "9.706549", "elevation": "178.10000610351563", "time": "2013-09-20T12:48:03.461Z"}, {"lat": "44.124455", "lng": "9.706625", "elevation": "176.6999969482422", "time": "2013-09-20T12:48:18.527Z"}, {"lat": "44.124454", "lng": "9.706628", "elevation": "176.1999969482422", "time": "2013-09-20T12:48:19.495Z"}, {"lat": "44.124452", "lng": "9.706645", "elevation": "174.10000610351563", "time": "2013-09-20T12:48:25.559Z"}, {"lat": "44.124451", "lng": "9.706647", "elevation": "174.0", "time": "2013-09-20T12:48:26.517Z"}, {"lat": "44.124445", "lng": "9.706657", "elevation": "172.89999389648438", "time": "2013-09-20T12:48:31.569Z"}, {"lat": "44.124444", "lng": "9.706659", "elevation": "173.0", "time": "2013-09-20T12:48:32.560Z"}, {"lat": "44.124443", "lng": "9.706661", "elevation": "172.6999969482422", "time": "2013-09-20T12:48:33.561Z"}, {"lat": "44.12444", "lng": "9.706667", "elevation": "171.8000030517578", "time": "2013-09-20T12:48:36.475Z"}, {"lat": "44.124437", "lng": "9.70667", "elevation": "171.60000610351563", "time": "2013-09-20T12:48:37.470Z"}, {"lat": "44.124409", "lng": "9.706687", "elevation": "170.5", "time": "2013-09-20T12:48:46.479Z"}, {"lat": "44.124408", "lng": "9.706689", "elevation": "169.8000030517578", "time": "2013-09-20T12:48:47.472Z"}, {"lat": "44.124407", "lng": "9.706693", "elevation": "169.60000610351563", "time": "2013-09-20T12:48:48.479Z"}, {"lat": "44.124402", "lng": "9.706717", "elevation": "169.6999969482422", "time": "2013-09-20T12:48:54.477Z"}, {"lat": "44.124401", "lng": "9.706718", "elevation": "169.6999969482422", "time": "2013-09-20T12:48:55.476Z"}, {"lat": "44.124399", "lng": "9.706725", "elevation": "169.60000610351563", "time": "2013-09-20T12:49:12.474Z"}, {"lat": "44.124399", "lng": "9.706731", "elevation": "169.60000610351563", "time": "2013-09-20T12:49:13.473Z"}, {"lat": "44.124433", "lng": "9.706832", "elevation": "162.3000030517578", "time": "2013-09-20T12:49:22.492Z"}, {"lat": "44.124436", "lng": "9.706845", "elevation": "161.8000030517578", "time": "2013-09-20T12:49:23.488Z"}, {"lat": "44.124378", "lng": "9.70694", "elevation": "160.6999969482422", "time": "2013-09-20T12:49:30.523Z"}, {"lat": "44.124371", "lng": "9.706949", "elevation": "160.6999969482422", "time": "2013-09-20T12:49:31.483Z"}, {"lat": "44.124356", "lng": "9.706976", "elevation": "160.8000030517578", "time": "2013-09-20T12:49:39.501Z"}, {"lat": "44.124356", "lng": "9.706977", "elevation": "160.89999389648438", "time": "2013-09-20T12:49:40.486Z"}, {"lat": "44.124355", "lng": "9.706983", "elevation": "159.60000610351563", "time": "2013-09-20T12:49:55.493Z"}, {"lat": "44.124357", "lng": "9.70699", "elevation": "159.1999969482422", "time": "2013-09-20T12:49:56.485Z"}, {"lat": "44.124397", "lng": "9.707086", "elevation": "159.1999969482422", "time": "2013-09-20T12:50:04.485Z"}, {"lat": "44.124403", "lng": "9.707097", "elevation": "159.60000610351563", "time": "2013-09-20T12:50:05.512Z"}, {"lat": "44.12445", "lng": "9.707187", "elevation": "157.5", "time": "2013-09-20T12:50:17.483Z"}, {"lat": "44.124449", "lng": "9.707187", "elevation": "157.8000030517578", "time": "2013-09-20T12:50:18.482Z"}, {"lat": "44.124453", "lng": "9.707198", "elevation": "158.10000610351563", "time": "2013-09-20T12:50:40.536Z"}, {"lat": "44.124457", "lng": "9.707203", "elevation": "156.89999389648438", "time": "2013-09-20T12:50:41.491Z"}, {"lat": "44.124518", "lng": "9.707285", "elevation": "158.10000610351563", "time": "2013-09-20T12:50:52.656Z"}, {"lat": "44.12452", "lng": "9.707295", "elevation": "158.60000610351563", "time": "2013-09-20T12:50:53.649Z"}, {"lat": "44.124515", "lng": "9.707414", "elevation": "158.0", "time": "2013-09-20T12:51:04.490Z"}, {"lat": "44.124513", "lng": "9.707434", "elevation": "157.39999389648438", "time": "2013-09-20T12:51:05.683Z"}, {"lat": "44.12446", "lng": "9.707516", "elevation": "159.60000610351563", "time": "2013-09-20T12:51:12.562Z"}, {"lat": "44.124451", "lng": "9.707528", "elevation": "161.10000610351563", "time": "2013-09-20T12:51:13.518Z"}, {"lat": "44.1244", "lng": "9.707616", "elevation": "162.1999969482422", "time": "2013-09-20T12:51:20.684Z"}, {"lat": "44.124394", "lng": "9.70763", "elevation": "162.0", "time": "2013-09-20T12:51:21.661Z"}, {"lat": "44.124326", "lng": "9.707697", "elevation": "159.5", "time": "2013-09-20T12:51:29.516Z"}, {"lat": "44.124322", "lng": "9.707712", "elevation": "158.39999389648438", "time": "2013-09-20T12:51:30.487Z"}, {"lat": "44.124296", "lng": "9.707822", "elevation": "157.5", "time": "2013-09-20T12:51:39.488Z"}, {"lat": "44.124289", "lng": "9.707829", "elevation": "158.10000610351563", "time": "2013-09-20T12:51:40.485Z"}, {"lat": "44.124213", "lng": "9.707878", "elevation": "160.10000610351563", "time": "2013-09-20T12:51:51.489Z"}, {"lat": "44.124205", "lng": "9.707883", "elevation": "159.89999389648438", "time": "2013-09-20T12:51:52.487Z"}, {"lat": "44.124127", "lng": "9.707928", "elevation": "159.8000030517578", "time": "2013-09-20T12:52:01.486Z"}, {"lat": "44.124119", "lng": "9.707933", "elevation": "160.39999389648438", "time": "2013-09-20T12:52:02.496Z"}, {"lat": "44.12404", "lng": "9.707982", "elevation": "160.3000030517578", "time": "2013-09-20T12:52:12.487Z"}, {"lat": "44.12403", "lng": "9.707983", "elevation": "160.60000610351563", "time": "2013-09-20T12:52:13.491Z"}, {"lat": "44.123946", "lng": "9.708006", "elevation": "160.5", "time": "2013-09-20T12:52:22.489Z"}, {"lat": "44.123936", "lng": "9.70801", "elevation": "160.6999969482422", "time": "2013-09-20T12:52:23.489Z"}, {"lat": "44.123856", "lng": "9.70806", "elevation": "159.0", "time": "2013-09-20T12:52:31.678Z"}, {"lat": "44.12385", "lng": "9.708069", "elevation": "158.89999389648438", "time": "2013-09-20T12:52:32.600Z"}, {"lat": "44.123791", "lng": "9.70815", "elevation": "156.0", "time": "2013-09-20T12:52:40.651Z"}, {"lat": "44.123784", "lng": "9.70816", "elevation": "156.8000030517578", "time": "2013-09-20T12:52:41.668Z"}, {"lat": "44.123718", "lng": "9.708225", "elevation": "155.5", "time": "2013-09-20T12:52:49.611Z"}, {"lat": "44.123711", "lng": "9.708235", "elevation": "154.8000030517578", "time": "2013-09-20T12:52:50.673Z"}, {"lat": "44.123644", "lng": "9.708297", "elevation": "154.60000610351563", "time": "2013-09-20T12:52:58.579Z"}, {"lat": "44.123633", "lng": "9.708301", "elevation": "154.5", "time": "2013-09-20T12:52:59.698Z"}, {"lat": "44.123547", "lng": "9.708334", "elevation": "151.1999969482422", "time": "2013-09-20T12:53:08.497Z"}, {"lat": "44.123539", "lng": "9.70834", "elevation": "150.60000610351563", "time": "2013-09-20T12:53:09.504Z"}, {"lat": "44.123486", "lng": "9.708428", "elevation": "147.60000610351563", "time": "2013-09-20T12:53:17.492Z"}, {"lat": "44.123481", "lng": "9.708442", "elevation": "147.39999389648438", "time": "2013-09-20T12:53:18.495Z"}, {"lat": "44.123423", "lng": "9.708533", "elevation": "148.8000030517578", "time": "2013-09-20T12:53:28.646Z"}, {"lat": "44.12342", "lng": "9.708543", "elevation": "148.89999389648438", "time": "2013-09-20T12:53:29.629Z"}, {"lat": "44.123342", "lng": "9.708599", "elevation": "147.1999969482422", "time": "2013-09-20T12:53:39.554Z"}, {"lat": "44.123333", "lng": "9.708604", "elevation": "145.5", "time": "2013-09-20T12:53:40.655Z"}, {"lat": "44.123279", "lng": "9.708686", "elevation": "144.39999389648438", "time": "2013-09-20T12:53:48.492Z"}, {"lat": "44.123273", "lng": "9.708699", "elevation": "143.6999969482422", "time": "2013-09-20T12:53:49.500Z"}, {"lat": "44.123238", "lng": "9.708806", "elevation": "143.1999969482422", "time": "2013-09-20T12:53:57.495Z"}, {"lat": "44.123227", "lng": "9.708813", "elevation": "144.10000610351563", "time": "2013-09-20T12:53:58.668Z"}, {"lat": "44.123139", "lng": "9.708827", "elevation": "143.8000030517578", "time": "2013-09-20T12:54:07.671Z"}, {"lat": "44.123132", "lng": "9.708825", "elevation": "143.89999389648438", "time": "2013-09-20T12:54:08.594Z"}, {"lat": "44.12305", "lng": "9.708873", "elevation": "145.5", "time": "2013-09-20T12:54:19.653Z"}, {"lat": "44.123044", "lng": "9.708883", "elevation": "146.89999389648438", "time": "2013-09-20T12:54:20.530Z"}, {"lat": "44.123033", "lng": "9.709003", "elevation": "142.1999969482422", "time": "2013-09-20T12:54:27.547Z"}, {"lat": "44.123037", "lng": "9.709016", "elevation": "142.0", "time": "2013-09-20T12:54:28.661Z"}, {"lat": "44.123044", "lng": "9.709024", "elevation": "141.6999969482422", "time": "2013-09-20T12:54:33.566Z"}, {"lat": "44.123044", "lng": "9.709024", "elevation": "141.39999389648438", "time": "2013-09-20T12:54:34.573Z"}, {"lat": "44.123045", "lng": "9.709027", "elevation": "140.8000030517578", "time": "2013-09-20T12:54:37.499Z"}, {"lat": "44.123046", "lng": "9.709033", "elevation": "140.0", "time": "2013-09-20T12:54:38.502Z"}, {"lat": "44.123049", "lng": "9.709143", "elevation": "141.89999389648438", "time": "2013-09-20T12:54:45.501Z"}, {"lat": "44.123042", "lng": "9.70916", "elevation": "143.6999969482422", "time": "2013-09-20T12:54:46.499Z"}, {"lat": "44.122993", "lng": "9.709248", "elevation": "144.10000610351563", "time": "2013-09-20T12:54:52.577Z"}, {"lat": "44.122987", "lng": "9.709261", "elevation": "144.39999389648438", "time": "2013-09-20T12:54:53.616Z"}, {"lat": "44.12295", "lng": "9.709362", "elevation": "143.60000610351563", "time": "2013-09-20T12:55:04.674Z"}, {"lat": "44.122939", "lng": "9.70937", "elevation": "144.1999969482422", "time": "2013-09-20T12:55:05.669Z"}, {"lat": "44.122904", "lng": "9.709478", "elevation": "141.1999969482422", "time": "2013-09-20T12:55:11.596Z"}, {"lat": "44.122901", "lng": "9.709496", "elevation": "140.8000030517578", "time": "2013-09-20T12:55:12.702Z"}, {"lat": "44.122878", "lng": "9.709545", "elevation": "136.0", "time": "2013-09-20T12:55:20.525Z"}, {"lat": "44.122881", "lng": "9.709537", "elevation": "135.8000030517578", "time": "2013-09-20T12:55:21.639Z"}, {"lat": "44.122882", "lng": "9.709527", "elevation": "136.3000030517578", "time": "2013-09-20T12:55:22.615Z"}, {"lat": "44.122811", "lng": "9.709459", "elevation": "139.8000030517578", "time": "2013-09-20T12:55:30.609Z"}, {"lat": "44.122801", "lng": "9.709451", "elevation": "139.1999969482422", "time": "2013-09-20T12:55:31.549Z"}, {"lat": "44.122742", "lng": "9.709389", "elevation": "138.60000610351563", "time": "2013-09-20T12:55:47.577Z"}, {"lat": "44.122741", "lng": "9.70939", "elevation": "138.6999969482422", "time": "2013-09-20T12:55:48.739Z"}, {"lat": "44.122741", "lng": "9.70938", "elevation": "138.89999389648438", "time": "2013-09-20T12:55:53.713Z"}, {"lat": "44.122739", "lng": "9.709376", "elevation": "137.6999969482422", "time": "2013-09-20T12:55:54.606Z"}, {"lat": "44.122705", "lng": "9.709331", "elevation": "139.0", "time": "2013-09-20T12:56:03.557Z"}, {"lat": "44.122706", "lng": "9.709335", "elevation": "138.89999389648438", "time": "2013-09-20T12:56:04.738Z"}] \ No newline at end of file diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/uk.lproj/InfoPlist.strings b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/uk.lproj/InfoPlist.strings new file mode 100644 index 0000000..477b28f --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/uk.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/vi.lproj/InfoPlist.strings b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/vi.lproj/InfoPlist.strings new file mode 100644 index 0000000..477b28f --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/vi.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/zh_CN.lproj/InfoPlist.strings b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/zh_CN.lproj/InfoPlist.strings new file mode 100644 index 0000000..477b28f --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/zh_CN.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/zh_TW.lproj/InfoPlist.strings b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/zh_TW.lproj/InfoPlist.strings new file mode 100644 index 0000000..477b28f --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Resources/zh_TW.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/SDKDemo-Info.plist b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/SDKDemo-Info.plist new file mode 100644 index 0000000..47cc809 --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/SDKDemo-Info.plist @@ -0,0 +1,51 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleDisplayName + ${PRODUCT_NAME} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + com.example.SDKDemos + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + LSRequiresIPhoneOS + + NSLocationWhenInUseUsageDescription + Show your location on the map + UILaunchStoryboardName + Launch + UIRequiredDeviceCapabilities + + armv7 + + UIStatusBarHidden + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/SDKDemo-Prefix.pch b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/SDKDemo-Prefix.pch new file mode 100644 index 0000000..f5560a7 --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/SDKDemo-Prefix.pch @@ -0,0 +1,14 @@ +// +// Prefix header for all source files of the 'SDKDemo' target in the 'Google Maps SDK for iOS' project +// + +#import + +#ifndef __IPHONE_6_0 +#warning "This project uses features only available in iOS SDK 6.0 and later." +#endif + +#ifdef __OBJC__ + #import + #import +#endif diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/SDKDemoAPIKey.h b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/SDKDemoAPIKey.h new file mode 100644 index 0000000..142b44f --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/SDKDemoAPIKey.h @@ -0,0 +1,10 @@ +/** + * To use GoogleMapsSDKDemos, please register an APIKey for your application + * and set it here. Your APIKey should be kept private. + * + * See documentation on getting an API Key for your API Project here: + * https://developers.google.com/maps/documentation/ios/start#get-key + */ + +#error Register for API Key and insert here. Then delete this line. +static NSString *const kAPIKey = @""; diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/SDKDemoAppDelegate.h b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/SDKDemoAppDelegate.h new file mode 100644 index 0000000..326053c --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/SDKDemoAppDelegate.h @@ -0,0 +1,17 @@ +#import + +@interface SDKDemoAppDelegate : UIResponder < + UIApplicationDelegate, + UISplitViewControllerDelegate> + +@property(strong, nonatomic) UIWindow *window; +@property(strong, nonatomic) UINavigationController *navigationController; +@property(strong, nonatomic) UISplitViewController *splitViewController; + +/** + * If the device is an iPad, this property controls the sample displayed in the + * right side of its split view controller. + */ +@property(strong, nonatomic) UIViewController *sample; + +@end diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/SDKDemoAppDelegate.m b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/SDKDemoAppDelegate.m new file mode 100644 index 0000000..7192043 --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/SDKDemoAppDelegate.m @@ -0,0 +1,102 @@ +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +#import "SDKDemos/SDKDemoAppDelegate.h" + +#import "SDKDemos/SDKDemoAPIKey.h" +#import "SDKDemos/SDKDemoMasterViewController.h" +#import + +@implementation SDKDemoAppDelegate { + id services_; +} + +@synthesize window = _window; + +- (BOOL)application:(UIApplication *)application + didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + NSLog(@"Build verison: %d", __apple_build_version__); + + if ([kAPIKey length] == 0) { + // Blow up if APIKey has not yet been set. + NSString *bundleId = [[NSBundle mainBundle] bundleIdentifier]; + NSString *format = @"Configure APIKey inside SDKDemoAPIKey.h for your " + @"bundle `%@`, see README.GoogleMapsSDKDemos for more information"; + @throw [NSException exceptionWithName:@"SDKDemoAppDelegate" + reason:[NSString stringWithFormat:format, bundleId] + userInfo:nil]; + } + [GMSServices provideAPIKey:kAPIKey]; + services_ = [GMSServices sharedServices]; + + // Log the required open source licenses! Yes, just NSLog-ing them is not + // enough but is good for a demo. + NSLog(@"Open source licenses:\n%@", [GMSServices openSourceLicenseInfo]); + + self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; + SDKDemoMasterViewController *master = [[SDKDemoMasterViewController alloc] init]; + master.appDelegate = self; + + if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) { + // This is an iPhone; configure the top-level navigation controller as the + // rootViewController, which contains the 'master' list of samples. + self.navigationController = + [[UINavigationController alloc] initWithRootViewController:master]; + + // Force non-translucent navigation bar for consistency of demo between + // iOS 6 and iOS 7. + self.navigationController.navigationBar.translucent = NO; + + self.window.rootViewController = self.navigationController; + } else { + // This is an iPad; configure a split-view controller that contains the + // the 'master' list of samples on the left side, and the current displayed + // sample on the right (begins empty). + UINavigationController *masterNavigationController = + [[UINavigationController alloc] initWithRootViewController:master]; + + UIViewController *empty = [[UIViewController alloc] init]; + UINavigationController *detailNavigationController = + [[UINavigationController alloc] initWithRootViewController:empty]; + + // Force non-translucent navigation bar for consistency of demo between + // iOS 6 and iOS 7. + detailNavigationController.navigationBar.translucent = NO; + + self.splitViewController = [[UISplitViewController alloc] init]; + self.splitViewController.delegate = master; + self.splitViewController.viewControllers = + @[masterNavigationController, detailNavigationController]; + self.splitViewController.presentsWithGesture = NO; + + self.window.rootViewController = self.splitViewController; + } + + [self.window makeKeyAndVisible]; + return YES; +} + +- (void)setSample:(UIViewController *)sample { + NSAssert([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad, + @"Expected device to be iPad inside setSample:"); + + // Finds the UINavigationController in the right side of the sample, and + // replace its displayed controller with the new sample. + UINavigationController *nav = + [self.splitViewController.viewControllers objectAtIndex:1]; + [nav setViewControllers:[NSArray arrayWithObject:sample] animated:NO]; +} + +- (UIViewController *)sample { + NSAssert([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad, + @"Expected device to be iPad inside sample"); + + // The current sample is the top-most VC in the right-hand pane of the + // splitViewController. + UINavigationController *nav = + [self.splitViewController.viewControllers objectAtIndex:1]; + return [[nav viewControllers] objectAtIndex:0]; +} + +@end diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/SDKDemoMasterViewController.h b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/SDKDemoMasterViewController.h new file mode 100644 index 0000000..27dab51 --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/SDKDemoMasterViewController.h @@ -0,0 +1,12 @@ +#import + +@class SDKDemoAppDelegate; + +@interface SDKDemoMasterViewController : UITableViewController < + UISplitViewControllerDelegate, + UITableViewDataSource, + UITableViewDelegate> + +@property(nonatomic, assign) SDKDemoAppDelegate *appDelegate; + +@end diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/SDKDemoMasterViewController.m b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/SDKDemoMasterViewController.m new file mode 100644 index 0000000..11c696d --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/SDKDemoMasterViewController.m @@ -0,0 +1,167 @@ +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +#import "SDKDemos/SDKDemoMasterViewController.h" + +#import "SDKDemos/PlacesSamples/Samples+Places.h" +#import "SDKDemos/SDKDemoAppDelegate.h" +#import +#import "SDKDemos/Samples/Samples.h" + +@implementation SDKDemoMasterViewController { + NSArray *demos_; + NSArray *demoSections_; + BOOL isPhone_; + UIPopoverController *popover_; + UIBarButtonItem *samplesButton_; + __weak UIViewController *controller_; + CLLocationManager *locationManager_; +} + +- (void)viewDidLoad { + [super viewDidLoad]; + + isPhone_ = [[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone; + + if (!isPhone_) { + self.clearsSelectionOnViewWillAppear = NO; + } else { + UIBarButtonItem *backButton = + [[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(@"Back", @"Back") + style:UIBarButtonItemStyleBordered + target:nil + action:nil]; + [self.navigationItem setBackBarButtonItem:backButton]; + } + + self.title = NSLocalizedString(@"Maps SDK Demos", @"Maps SDK Demos"); + self.title = [NSString stringWithFormat:@"%@: %@", self.title, [GMSServices SDKVersion]]; + + self.tableView.autoresizingMask = + UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleWidth; + self.tableView.delegate = self; + self.tableView.dataSource = self; + + demoSections_ = [Samples loadSections]; + demos_ = [Samples loadDemos]; + [self addPlacesDemos]; + + if (!isPhone_) { + [self loadDemo:0 atIndex:0]; + } +} +- (void)addPlacesDemos { + NSMutableArray *sections = [NSMutableArray arrayWithArray:demoSections_]; + [sections insertObject:@"Places" atIndex:0]; + demoSections_ = [sections copy]; + + NSMutableArray *demos = [NSMutableArray arrayWithArray:demos_]; + [demos insertObject:[Samples placesDemos] + atIndex:0]; + demos_ = [demos copy]; +} + +#pragma mark - UITableViewController + +- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { + return demoSections_.count; +} + +- (CGFloat)tableView:(UITableView *)tableView + heightForHeaderInSection:(NSInteger)section { + return 35.0; +} + +- (NSString *)tableView:(UITableView *)tableView + titleForHeaderInSection:(NSInteger)section { + return [demoSections_ objectAtIndex:section]; +} + +- (NSInteger)tableView:(UITableView *)tableView + numberOfRowsInSection:(NSInteger)section { + return [[demos_ objectAtIndex: section] count]; +} + +- (UITableViewCell *)tableView:(UITableView *)tableView + cellForRowAtIndexPath:(NSIndexPath *)indexPath { + static NSString *cellIdentifier = @"Cell"; + UITableViewCell *cell = + [tableView dequeueReusableCellWithIdentifier:cellIdentifier]; + if (cell == nil) { + cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle + reuseIdentifier:cellIdentifier]; + + if (isPhone_) { + [cell setAccessoryType:UITableViewCellAccessoryDisclosureIndicator]; + } + } + + NSDictionary *demo = [[demos_ objectAtIndex:indexPath.section] + objectAtIndex:indexPath.row]; + cell.textLabel.text = [demo objectForKey:@"title"]; + cell.detailTextLabel.text = [demo objectForKey:@"description"]; + + return cell; +} + +- (void)tableView:(UITableView *)tableView + didSelectRowAtIndexPath:(NSIndexPath *)indexPath { + // The user has chosen a sample; load it and clear the selection! + [self loadDemo:indexPath.section atIndex:indexPath.row]; + [tableView deselectRowAtIndexPath:indexPath animated:YES]; +} + +#pragma mark - Split view + +- (void)splitViewController:(UISplitViewController *)splitController + willHideViewController:(UIViewController *)viewController + withBarButtonItem:(UIBarButtonItem *)barButtonItem + forPopoverController:(UIPopoverController *)popoverController { + popover_ = popoverController; + samplesButton_ = barButtonItem; + samplesButton_.title = NSLocalizedString(@"Samples", @"Samples"); + samplesButton_.style = UIBarButtonItemStyleDone; + [self updateSamplesButton]; +} + +- (void)splitViewController:(UISplitViewController *)splitController + willShowViewController:(UIViewController *)viewController + invalidatingBarButtonItem:(UIBarButtonItem *)barButtonItem { + popover_ = nil; + samplesButton_ = nil; + [self updateSamplesButton]; +} + +#pragma mark - Private methods + +- (void)loadDemo:(NSUInteger)section + atIndex:(NSUInteger)index { + NSDictionary *demo = [[demos_ objectAtIndex:section] objectAtIndex:index]; + UIViewController *controller = + [[[demo objectForKey:@"controller"] alloc] init]; + controller_ = controller; + + if (controller != nil) { + controller.title = [demo objectForKey:@"title"]; + + if (isPhone_) { + [self.navigationController pushViewController:controller animated:YES]; + } else { + [self.appDelegate setSample:controller]; + [popover_ dismissPopoverAnimated:YES]; + } + + [self updateSamplesButton]; + } +} + +// This method is invoked when the left 'back' button in the split view +// controller on iPad should be updated (either made visible or hidden). +// It assumes that the left bar button item may be safely modified to contain +// the samples button. +- (void)updateSamplesButton { + controller_.navigationItem.leftBarButtonItem = samplesButton_; +} + +@end diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/AnimatedCurrentLocationViewController.h b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/AnimatedCurrentLocationViewController.h new file mode 100644 index 0000000..fd45b85 --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/AnimatedCurrentLocationViewController.h @@ -0,0 +1,9 @@ + +#import +#import + +#import + +@interface AnimatedCurrentLocationViewController : UIViewController + +@end diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/AnimatedCurrentLocationViewController.m b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/AnimatedCurrentLocationViewController.m new file mode 100644 index 0000000..dc50540 --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/AnimatedCurrentLocationViewController.m @@ -0,0 +1,91 @@ +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +#import "SDKDemos/Samples/AnimatedCurrentLocationViewController.h" + +@implementation AnimatedCurrentLocationViewController { + CLLocationManager *_manager; + GMSMapView *_mapView; + GMSMarker *_locationMarker; + +} + +- (void)viewDidLoad { + [super viewDidLoad]; + + GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:38.8879 + longitude:-77.0200 + zoom:17]; + _mapView = [GMSMapView mapWithFrame:CGRectZero camera:camera]; + _mapView.settings.myLocationButton = NO; + _mapView.settings.indoorPicker = NO; + + self.view = _mapView; + + // Setup location services + if (![CLLocationManager locationServicesEnabled]) { + NSLog(@"Please enable location services"); + return; + } + + if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusDenied) { + NSLog(@"Please authorize location services"); + return; + } + + _manager = [[CLLocationManager alloc] init]; + _manager.delegate = self; + _manager.desiredAccuracy = kCLLocationAccuracyBest; + _manager.distanceFilter = 5.0f; + [_manager startUpdatingLocation]; + +} + +#pragma mark - CLLocationManagerDelegate + +- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error { + if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusDenied) { + NSLog(@"Please authorize location services"); + return; + } + + NSLog(@"CLLocationManager error: %@", error.localizedFailureReason); + return; +} + +- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations { + CLLocation *location = [locations lastObject]; + + if (_locationMarker == nil) { + _locationMarker = [[GMSMarker alloc] init]; + _locationMarker.position = CLLocationCoordinate2DMake(-33.86, 151.20); + + // Animated walker images derived from an www.angryanimator.com tutorial. + // See: http://www.angryanimator.com/word/2010/11/26/tutorial-2-walk-cycle/ + + NSArray *frames = @[[UIImage imageNamed:@"step1"], + [UIImage imageNamed:@"step2"], + [UIImage imageNamed:@"step3"], + [UIImage imageNamed:@"step4"], + [UIImage imageNamed:@"step5"], + [UIImage imageNamed:@"step6"], + [UIImage imageNamed:@"step7"], + [UIImage imageNamed:@"step8"]]; + + _locationMarker.icon = [UIImage animatedImageWithImages:frames duration:0.8]; + _locationMarker.groundAnchor = CGPointMake(0.5f, 0.97f); // Taking into account walker's shadow + _locationMarker.map = _mapView; + } else { + [CATransaction begin]; + [CATransaction setAnimationDuration:2.0]; + _locationMarker.position = location.coordinate; + [CATransaction commit]; + } + + GMSCameraUpdate *move = [GMSCameraUpdate setTarget:location.coordinate zoom:17]; + [_mapView animateWithCameraUpdate:move]; +} + + +@end diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/BasicMapViewController.h b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/BasicMapViewController.h new file mode 100644 index 0000000..d6611e3 --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/BasicMapViewController.h @@ -0,0 +1,5 @@ +#import + +@interface BasicMapViewController : UIViewController + +@end diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/BasicMapViewController.m b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/BasicMapViewController.m new file mode 100644 index 0000000..7ab1dbd --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/BasicMapViewController.m @@ -0,0 +1,19 @@ +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +#import "SDKDemos/Samples/BasicMapViewController.h" + +#import + +@implementation BasicMapViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:-33.868 + longitude:151.2086 + zoom:6]; + self.view = [GMSMapView mapWithFrame:CGRectZero camera:camera]; +} + +@end diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/CameraViewController.h b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/CameraViewController.h new file mode 100644 index 0000000..0853237 --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/CameraViewController.h @@ -0,0 +1,5 @@ +#import + +@interface CameraViewController : UIViewController + +@end diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/CameraViewController.m b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/CameraViewController.m new file mode 100644 index 0000000..7291897 --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/CameraViewController.m @@ -0,0 +1,61 @@ +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +#import "SDKDemos/Samples/CameraViewController.h" + +#import + +@implementation CameraViewController { + GMSMapView *_mapView; + NSTimer *timer; +} + +- (void)viewDidLoad { + [super viewDidLoad]; + GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:-37.809487 + longitude:144.965699 + zoom:20 + bearing:0 + viewingAngle:0]; + _mapView = [GMSMapView mapWithFrame:CGRectZero camera:camera]; + _mapView.settings.zoomGestures = NO; + _mapView.settings.scrollGestures = NO; + _mapView.settings.rotateGestures = NO; + _mapView.settings.tiltGestures = NO; + + self.view = _mapView; +} + +- (void)moveCamera { + GMSCameraPosition *camera = _mapView.camera; + float zoom = fmaxf(camera.zoom - 0.1f, 17.5f); + + GMSCameraPosition *newCamera = + [[GMSCameraPosition alloc] initWithTarget:camera.target + zoom:zoom + bearing:camera.bearing + 10 + viewingAngle:camera.viewingAngle + 10]; + [_mapView animateToCameraPosition:newCamera]; +} + +- (void)viewDidAppear:(BOOL)animated { + [super viewDidAppear:animated]; + timer = [NSTimer scheduledTimerWithTimeInterval:1.f/30.f + target:self + selector:@selector(moveCamera) + userInfo:nil + repeats:YES]; +} + +- (void)viewDidDisappear:(BOOL)animated { + [super viewDidDisappear:animated]; + [timer invalidate]; +} + +- (void)didReceiveMemoryWarning { + [super didReceiveMemoryWarning]; + [timer invalidate]; +} + +@end diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/CustomIndoorViewController.h b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/CustomIndoorViewController.h new file mode 100644 index 0000000..3379794 --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/CustomIndoorViewController.h @@ -0,0 +1,4 @@ +#import + +@interface CustomIndoorViewController : UIViewController +@end diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/CustomIndoorViewController.m b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/CustomIndoorViewController.m new file mode 100644 index 0000000..d2f0e3c --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/CustomIndoorViewController.m @@ -0,0 +1,139 @@ +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +#import "SDKDemos/Samples/CustomIndoorViewController.h" + +#import + +@interface CustomIndoorViewController () < + GMSIndoorDisplayDelegate, + UIPickerViewDelegate, + UIPickerViewDataSource> + +@end + +@implementation CustomIndoorViewController { + GMSMapView *_mapView; + UIPickerView *_levelPickerView; + NSArray *_levels; +} + +- (void)viewDidLoad { + [super viewDidLoad]; + GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:37.78318 + longitude:-122.403874 + zoom:18]; + + // set backgroundColor, otherwise UIPickerView fades into the background + self.view.backgroundColor = [UIColor grayColor]; + + _mapView = [GMSMapView mapWithFrame:CGRectZero camera:camera]; + _mapView.settings.myLocationButton = NO; + _mapView.settings.indoorPicker = NO; // We are implementing a custom level picker. + + _mapView.indoorEnabled = YES; // Defaults to YES. Set to NO to hide indoor maps. + _mapView.indoorDisplay.delegate = self; + _mapView.translatesAutoresizingMaskIntoConstraints = NO; + [self.view addSubview:_mapView]; + + // This UIPickerView will be populated with the levels of the active building. + _levelPickerView = [[UIPickerView alloc] init]; + _levelPickerView.delegate = self; + _levelPickerView.dataSource = self; + _levelPickerView.showsSelectionIndicator = YES; + _levelPickerView.translatesAutoresizingMaskIntoConstraints = NO; + [self.view addSubview:_levelPickerView]; + + // The height of the UIPickerView, used below in the vertical constraint + NSDictionary *metrics = @{@"height": @180.0}; + NSDictionary *views = NSDictionaryOfVariableBindings(_mapView, _levelPickerView); + + // Constraining the map to the full width of the display. + // The |_levelPickerView| is constrained below with the NSLayoutFormatAlignAll* + // See http://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/AutolayoutPG/Articles/formatLanguage.html + [self.view addConstraints:[NSLayoutConstraint + constraintsWithVisualFormat:@"|[_mapView]|" + options:0 + metrics:metrics + views:views]]; + + // Constraining the _mapView and the _levelPickerView as siblings taking + // the full height of the display, with _levelPickerView at 200 points high + [self.view addConstraints:[NSLayoutConstraint + constraintsWithVisualFormat:@"V:|[_mapView][_levelPickerView(height)]|" + options:NSLayoutFormatAlignAllLeft|NSLayoutFormatAlignAllRight + metrics:metrics + views:views]]; +} + +#pragma mark - GMSIndoorDisplayDelegate + +- (void)didChangeActiveBuilding:(GMSIndoorBuilding *)building { + // Everytime we change active building force the picker to re-display the labels. + + NSMutableArray *levels = [NSMutableArray array]; + if (building.underground) { + // If this building is completely underground, add a fake 'top' floor. This must be the 'boxed' + // nil, [NSNull null], as NSArray/NSMutableArray cannot contain nils. + [levels addObject:[NSNull null]]; + } + [levels addObjectsFromArray:building.levels]; + _levels = [levels copy]; + + [_levelPickerView reloadAllComponents]; + [_levelPickerView selectRow:-1 inComponent:0 animated:NO]; + + // UIPickerView insists on having some data; disable interaction if there's no levels. + _levelPickerView.userInteractionEnabled = ([_levels count] > 0); +} + +- (void)didChangeActiveLevel:(GMSIndoorLevel *)level { + // On level change, sync our level picker's selection to the IndoorDisplay. + if (level == nil) { + level = (id)[NSNull null]; // box nil to NSNull for use in NSArray + } + NSUInteger index = [_levels indexOfObject:level]; + if (index != NSNotFound) { + NSInteger currentlySelectedLevel = [_levelPickerView selectedRowInComponent:0]; + if ((NSInteger)index != currentlySelectedLevel) { + [_levelPickerView selectRow:index inComponent:0 animated:NO]; + } + } +} + +#pragma mark - UIPickerViewDelegate + +- (void)pickerView:(UIPickerView *)pickerView + didSelectRow:(NSInteger)row + inComponent:(NSInteger)component { + // On user selection of a level in the picker, set the right level in IndoorDisplay + id level = _levels[row]; + if (level == [NSNull null]) { + level = nil; // unbox NSNull + } + [_mapView.indoorDisplay setActiveLevel:level]; +} + +- (NSString *)pickerView:(UIPickerView *)pickerView + titleForRow:(NSInteger)row + forComponent:(NSInteger)component { + id object = _levels[row]; + if (object == [NSNull null]) { + return @"\u2014"; // use an em dash for 'above ground' + } + GMSIndoorLevel *level = object; + return level.name; +} + +#pragma mark - UIPickerViewDataSource + +- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView { + return 1; +} + +- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component { + return [_levels count]; +} + +@end diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/CustomMarkersViewController.h b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/CustomMarkersViewController.h new file mode 100644 index 0000000..f5b839f --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/CustomMarkersViewController.h @@ -0,0 +1,5 @@ +#import + +@interface CustomMarkersViewController : UIViewController + +@end diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/CustomMarkersViewController.m b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/CustomMarkersViewController.m new file mode 100644 index 0000000..249e4cb --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/CustomMarkersViewController.m @@ -0,0 +1,111 @@ +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +#import "SDKDemos/Samples/CustomMarkersViewController.h" + +#import + +static int kMarkerCount = 0; + +// Returns a random value from 0-1.0f. +static CGFloat randf() { + return (((float)arc4random()/0x100000000)*1.0f); +} + +@implementation CustomMarkersViewController { + GMSMapView *_mapView; +} + +- (void)viewDidLoad { + [super viewDidLoad]; + GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:-37.81969 + longitude:144.966085 + zoom:4]; + _mapView = [GMSMapView mapWithFrame:CGRectZero camera:camera]; + [self addDefaultMarkers]; + + // Add a button which adds random markers to the map. + UIBarButtonItem *addButton = + [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd + target:self + action:@selector(didTapAdd)]; + addButton.accessibilityLabel = @"Add Markers"; + UIBarButtonItem *clearButton = + [[UIBarButtonItem alloc] initWithTitle:@"Clear Markers" + style:UIBarButtonItemStylePlain + target:self + action:@selector(didTapClear)]; + self.navigationItem.rightBarButtonItems = @[ addButton, clearButton ]; + + self.view = _mapView; +} + +- (void)addDefaultMarkers { + // Add a custom 'glow' marker around Sydney. + GMSMarker *sydneyMarker = [[GMSMarker alloc] init]; + sydneyMarker.title = @"Sydney!"; + sydneyMarker.icon = [UIImage imageNamed:@"glow-marker"]; + sydneyMarker.position = CLLocationCoordinate2DMake(-33.8683, 151.2086); + sydneyMarker.map = _mapView; + + // Add a custom 'arrow' marker pointing to Melbourne. + GMSMarker *melbourneMarker = [[GMSMarker alloc] init]; + melbourneMarker.title = @"Melbourne!"; + melbourneMarker.icon = [UIImage imageNamed:@"arrow"]; + melbourneMarker.position = CLLocationCoordinate2DMake(-37.81969, 144.966085); + melbourneMarker.map = _mapView; +} + +- (void)didTapAdd { + for (int i = 0; i < 10; ++i) { + // Add a marker every 0.25 seconds for the next ten markers, randomly + // within the bounds of the camera as it is at that point. + double delayInSeconds = (i * 0.25); + dispatch_time_t popTime = + dispatch_time(DISPATCH_TIME_NOW, + (int64_t)(delayInSeconds * NSEC_PER_SEC)); + dispatch_after(popTime, dispatch_get_main_queue(), ^(void) { + GMSVisibleRegion region = [_mapView.projection visibleRegion]; + GMSCoordinateBounds *bounds = + [[GMSCoordinateBounds alloc] initWithRegion:region]; + [self addMarkerInBounds:bounds]; + }); + } +} + +- (void)addMarkerInBounds:(GMSCoordinateBounds *)bounds { + CLLocationDegrees latitude = bounds.southWest.latitude + + randf() * (bounds.northEast.latitude - bounds.southWest.latitude); + + // If the visible region crosses the antimeridian (the right-most point is + // "smaller" than the left-most point), adjust the longitude accordingly. + BOOL offset = (bounds.northEast.longitude < bounds.southWest.longitude); + CLLocationDegrees longitude = bounds.southWest.longitude + randf() * + (bounds.northEast.longitude - bounds.southWest.longitude + (offset ? + 360 : 0)); + if (longitude > 180.f) { + longitude -= 360.f; + } + + UIColor *color = + [UIColor colorWithHue:randf() saturation:1.f brightness:1.f alpha:1.0f]; + + CLLocationCoordinate2D position = + CLLocationCoordinate2DMake(latitude, longitude); + GMSMarker *marker = [GMSMarker markerWithPosition:position]; + marker.title = [NSString stringWithFormat:@"Marker #%d", ++kMarkerCount]; + marker.appearAnimation = kGMSMarkerAnimationPop; + marker.icon = [GMSMarker markerImageWithColor:color]; + + marker.rotation = (randf()-0.5f)*20; // rotate between -20 and +20 degrees + + marker.map = _mapView; +} + +- (void)didTapClear { + [_mapView clear]; + [self addDefaultMarkers]; +} + +@end diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/DoubleMapViewController.h b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/DoubleMapViewController.h new file mode 100644 index 0000000..0a1d237 --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/DoubleMapViewController.h @@ -0,0 +1,5 @@ +#import + +@interface DoubleMapViewController : UIViewController + +@end diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/DoubleMapViewController.m b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/DoubleMapViewController.m new file mode 100644 index 0000000..0948acc --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/DoubleMapViewController.m @@ -0,0 +1,65 @@ +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +#import "SDKDemos/Samples/DoubleMapViewController.h" + +#import + +@interface DoubleMapViewController () +@end + +@implementation DoubleMapViewController { + GMSMapView *_mapView; + GMSMapView *_boundMapView; +} + ++ (GMSCameraPosition *)defaultCamera { + return [GMSCameraPosition cameraWithLatitude:37.7847 + longitude:-122.41 + zoom:5]; +} + +- (void)viewDidLoad { + [super viewDidLoad]; + + // Two map views, second one has its camera target controlled by the first. + CGRect frame = self.view.bounds; + frame.size.height = frame.size.height / 2; + _mapView = [GMSMapView mapWithFrame:frame camera:[DoubleMapViewController defaultCamera]]; + _mapView.autoresizingMask = UIViewAutoresizingFlexibleWidth | + UIViewAutoresizingFlexibleHeight | + UIViewAutoresizingFlexibleBottomMargin; + + _mapView.delegate = self; + [self.view addSubview:_mapView]; + + frame = self.view.bounds; + frame.size.height = frame.size.height / 2; + frame.origin.y = frame.size.height; + _boundMapView = + [GMSMapView mapWithFrame:frame camera:[DoubleMapViewController defaultCamera]]; + _boundMapView.autoresizingMask = UIViewAutoresizingFlexibleWidth | + UIViewAutoresizingFlexibleHeight | + UIViewAutoresizingFlexibleTopMargin; + _boundMapView.settings.scrollGestures = NO; + + [self.view addSubview:_boundMapView]; +} + +- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation + duration:(NSTimeInterval)duration { + CGRect frame = self.view.bounds; + frame.size.height = frame.size.height / 2; + _mapView.frame = frame; +} + +- (void)mapView:(GMSMapView *)mapView didChangeCameraPosition:(GMSCameraPosition *)position { + GMSCameraPosition *previousCamera = _boundMapView.camera; + _boundMapView.camera = [GMSCameraPosition cameraWithTarget:position.target + zoom:previousCamera.zoom + bearing:previousCamera.bearing + viewingAngle:previousCamera.viewingAngle]; +} + +@end diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/FitBoundsViewController.h b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/FitBoundsViewController.h new file mode 100644 index 0000000..3cc38b0 --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/FitBoundsViewController.h @@ -0,0 +1,5 @@ +#import + +@interface FitBoundsViewController : UIViewController + +@end diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/FitBoundsViewController.m b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/FitBoundsViewController.m new file mode 100644 index 0000000..f730201 --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/FitBoundsViewController.m @@ -0,0 +1,82 @@ +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +#import "SDKDemos/Samples/FitBoundsViewController.h" + +#import + +@interface FitBoundsViewController () +@end + +@implementation FitBoundsViewController { + GMSMapView *_mapView; + NSMutableArray *_markers; +} + +- (void)viewDidLoad { + [super viewDidLoad]; + GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:-37.81969 + longitude:144.966085 + zoom:4]; + _mapView = [GMSMapView mapWithFrame:CGRectZero camera:camera]; + _mapView.delegate = self; + self.view = _mapView; + + // Add a default marker around Sydney. + GMSMarker *sydneyMarker = [[GMSMarker alloc] init]; + sydneyMarker.title = @"Sydney!"; + sydneyMarker.icon = [UIImage imageNamed:@"glow-marker"]; + sydneyMarker.position = CLLocationCoordinate2DMake(-33.8683, 151.2086); + sydneyMarker.map = _mapView; + + GMSMarker *anotherSydneyMarker = [[GMSMarker alloc] init]; + anotherSydneyMarker.title = @"Sydney 2!"; + anotherSydneyMarker.icon = [UIImage imageNamed:@"glow-marker"]; + anotherSydneyMarker.position = CLLocationCoordinate2DMake(-33.8683, 149.2086); + anotherSydneyMarker.map = _mapView; + + // Create a list of markers, adding the Sydney marker. + _markers = [NSMutableArray arrayWithObject:sydneyMarker]; + [_markers addObject:anotherSydneyMarker]; + + // Create a button that, when pressed, updates the camera to fit the bounds + // of the specified markers. + UIBarButtonItem *fitBoundsButton = + [[UIBarButtonItem alloc] initWithTitle:@"Fit Bounds" + style:UIBarButtonItemStylePlain + target:self + action:@selector(didTapFitBounds)]; + self.navigationItem.rightBarButtonItem = fitBoundsButton; +} + +- (void)didTapFitBounds { + GMSCoordinateBounds *bounds; + for (GMSMarker *marker in _markers) { + if (bounds == nil) { + bounds = [[GMSCoordinateBounds alloc] initWithCoordinate:marker.position + coordinate:marker.position]; + } + bounds = [bounds includingCoordinate:marker.position]; + } + GMSCameraUpdate *update = [GMSCameraUpdate fitBounds:bounds + withPadding:50.0f]; + [_mapView moveCamera:update]; +} + +#pragma mark - GMSMapViewDelegate + +- (void)mapView:(GMSMapView *)mapView + didLongPressAtCoordinate:(CLLocationCoordinate2D)coordinate { + GMSMarker *marker = [[GMSMarker alloc] init]; + marker.title = [NSString stringWithFormat:@"Marker at: %.2f,%.2f", + coordinate.latitude, coordinate.longitude]; + marker.position = coordinate; + marker.appearAnimation = kGMSMarkerAnimationPop; + marker.map = _mapView; + + // Add the new marker to the list of markers. + [_markers addObject:marker]; +} + +@end diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/FixedPanoramaViewController.h b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/FixedPanoramaViewController.h new file mode 100644 index 0000000..29968c5 --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/FixedPanoramaViewController.h @@ -0,0 +1,5 @@ +#import + +@interface FixedPanoramaViewController : UIViewController + +@end diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/FixedPanoramaViewController.m b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/FixedPanoramaViewController.m new file mode 100644 index 0000000..0ef880e --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/FixedPanoramaViewController.m @@ -0,0 +1,33 @@ +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +#import "SDKDemos/Samples/FixedPanoramaViewController.h" + +#import + +static CLLocationCoordinate2D kPanoramaNear = {-33.732022, 150.312114}; + +@interface FixedPanoramaViewController () +@end + +@implementation FixedPanoramaViewController { + GMSPanoramaView *_view; +} + +- (void)viewDidLoad { + [super viewDidLoad]; + + _view = [GMSPanoramaView panoramaWithFrame:CGRectZero + nearCoordinate:kPanoramaNear]; + _view.camera = [GMSPanoramaCamera cameraWithHeading:180 + pitch:-10 + zoom:0]; + _view.delegate = self; + _view.orientationGestures = NO; + _view.navigationGestures = NO; + _view.navigationLinksHidden = YES; + self.view = _view; +} + +@end diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/GeocoderViewController.h b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/GeocoderViewController.h new file mode 100644 index 0000000..26bf09d --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/GeocoderViewController.h @@ -0,0 +1,7 @@ +#import + +#import + +@interface GeocoderViewController : UIViewController + +@end diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/GeocoderViewController.m b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/GeocoderViewController.m new file mode 100644 index 0000000..bc830f8 --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/GeocoderViewController.m @@ -0,0 +1,53 @@ +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +#import "SDKDemos/Samples/GeocoderViewController.h" + +#import + +@implementation GeocoderViewController { + GMSMapView *mapView_; + GMSGeocoder *geocoder_; +} + +- (void)viewDidLoad { + [super viewDidLoad]; + GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:-33.868 + longitude:151.2086 + zoom:12]; + + mapView_ = [GMSMapView mapWithFrame:CGRectZero camera:camera]; + mapView_.delegate = self; + + geocoder_ = [[GMSGeocoder alloc] init]; + + self.view = mapView_; +} + +- (void)mapView:(GMSMapView *)mapView + didLongPressAtCoordinate:(CLLocationCoordinate2D)coordinate { + // On a long press, reverse geocode this location. + GMSReverseGeocodeCallback handler = ^(GMSReverseGeocodeResponse *response, NSError *error) { + GMSAddress *address = response.firstResult; + if (address) { + NSLog(@"Geocoder result: %@", address); + + GMSMarker *marker = [GMSMarker markerWithPosition:address.coordinate]; + + marker.title = [[address lines] firstObject]; + if ([[address lines] count] > 1) { + marker.snippet = [[address lines] objectAtIndex:1]; + } + + marker.appearAnimation = kGMSMarkerAnimationPop; + marker.map = mapView_; + } else { + NSLog(@"Could not reverse geocode point (%f,%f): %@", + coordinate.latitude, coordinate.longitude, error); + } + }; + [geocoder_ reverseGeocodeCoordinate:coordinate completionHandler:handler]; +} + +@end diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/GestureControlViewController.h b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/GestureControlViewController.h new file mode 100644 index 0000000..fda8840 --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/GestureControlViewController.h @@ -0,0 +1,5 @@ +#import + +@interface GestureControlViewController : UIViewController + +@end diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/GestureControlViewController.m b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/GestureControlViewController.m new file mode 100644 index 0000000..556af4a --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/GestureControlViewController.m @@ -0,0 +1,59 @@ +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +#import "SDKDemos/Samples/GestureControlViewController.h" + +#import + +@implementation GestureControlViewController { + GMSMapView *mapView_; + UISwitch *zoomSwitch_; +} + +- (void)viewDidLoad { + [super viewDidLoad]; + GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:-25.5605 + longitude:133.605097 + zoom:3]; + + mapView_ = [GMSMapView mapWithFrame:CGRectZero camera:camera]; + mapView_.autoresizingMask = + UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + + self.view = [[UIView alloc] initWithFrame:CGRectZero]; + [self.view addSubview:mapView_]; + + UIView *holder = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 0, 59)]; + holder.autoresizingMask = + UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleBottomMargin; + holder.backgroundColor = [UIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:0.8f]; + [self.view addSubview:holder]; + + // Zoom label. + UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(16, 16, 200, 29)]; + label.text = @"Zooming?"; + label.font = [UIFont boldSystemFontOfSize:18.0f]; + label.textAlignment = NSTextAlignmentLeft; + label.backgroundColor = [UIColor clearColor]; + label.layer.shadowColor = [[UIColor whiteColor] CGColor]; + label.layer.shadowOffset = CGSizeMake(0.0f, 1.0f); + label.layer.shadowOpacity = 1.0f; + label.layer.shadowRadius = 0.0f; + [holder addSubview:label]; + + // Control zooming. + zoomSwitch_ = [[UISwitch alloc] initWithFrame:CGRectMake(-90, 16, 0, 0)]; + zoomSwitch_.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin; + [zoomSwitch_ addTarget:self + action:@selector(didChangeZoomSwitch) + forControlEvents:UIControlEventValueChanged]; + zoomSwitch_.on = YES; + [holder addSubview:zoomSwitch_]; +} + +- (void)didChangeZoomSwitch { + mapView_.settings.zoomGestures = zoomSwitch_.isOn; +} + +@end diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/GradientPolylinesViewController.h b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/GradientPolylinesViewController.h new file mode 100644 index 0000000..2de863c --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/GradientPolylinesViewController.h @@ -0,0 +1,5 @@ +#import + +@interface GradientPolylinesViewController : UIViewController + +@end diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/GradientPolylinesViewController.m b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/GradientPolylinesViewController.m new file mode 100644 index 0000000..13b51e4 --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/GradientPolylinesViewController.m @@ -0,0 +1,76 @@ +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +#import "SDKDemos/Samples/GradientPolylinesViewController.h" + +#import + + +@implementation GradientPolylinesViewController { + GMSMapView *mapView_; + GMSPolyline *polyline_; + NSMutableArray *trackData_; +} + +- (void)viewDidLoad { + [super viewDidLoad]; + GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:44.1314 + longitude:9.6921 + zoom:14.059f + bearing:328.f + viewingAngle:40.f]; + mapView_ = [GMSMapView mapWithFrame:CGRectZero camera:camera]; + self.view = mapView_; + + [self parseTrackFile]; + [polyline_ setSpans:[self gradientSpans]]; +} + +- (NSArray *)gradientSpans { + NSMutableArray *colorSpans = [NSMutableArray array]; + NSUInteger count = [trackData_ count]; + UIColor *prevColor; + for (NSUInteger i = 0; i < count; i++) { + double elevation = [[[trackData_ objectAtIndex:i] objectForKey:@"elevation"] doubleValue]; + + UIColor *toColor = [UIColor colorWithHue:(float)elevation/700 + saturation:1.f + brightness:.9f + alpha:1.f]; + + if (prevColor == nil) { + prevColor = toColor; + } + + GMSStrokeStyle *style = [GMSStrokeStyle gradientFromColor:prevColor toColor:toColor]; + [colorSpans addObject:[GMSStyleSpan spanWithStyle:style]]; + + prevColor = toColor; + } + return colorSpans; +} + +- (void)parseTrackFile { + NSString *filePath = [[NSBundle mainBundle] pathForResource:@"track" ofType:@"json"]; + NSData *data = [NSData dataWithContentsOfFile:filePath]; + NSArray *json = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil]; + trackData_ = [[NSMutableArray alloc] init]; + GMSMutablePath *path = [GMSMutablePath path]; + + for (NSUInteger i = 0; i < [json count]; i++) { + NSDictionary *info = [json objectAtIndex:i]; + NSNumber *elevation = [info objectForKey:@"elevation"]; + CLLocationDegrees lat = [[info objectForKey:@"lat"] doubleValue]; + CLLocationDegrees lng = [[info objectForKey:@"lng"] doubleValue]; + CLLocation *loc = [[CLLocation alloc] initWithLatitude:lat longitude:lng]; + [trackData_ addObject:@{@"loc": loc, @"elevation": elevation}]; + [path addLatitude:lat longitude:lng]; + } + + polyline_ = [GMSPolyline polylineWithPath:path]; + polyline_.strokeWidth = 6; + polyline_.map = mapView_; +} + +@end diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/GroundOverlayViewController.h b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/GroundOverlayViewController.h new file mode 100644 index 0000000..e9bfa76 --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/GroundOverlayViewController.h @@ -0,0 +1,5 @@ +#import + +@interface GroundOverlayViewController : UIViewController + +@end diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/GroundOverlayViewController.m b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/GroundOverlayViewController.m new file mode 100644 index 0000000..bfb200a --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/GroundOverlayViewController.m @@ -0,0 +1,41 @@ +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +#import "SDKDemos/Samples/GroundOverlayViewController.h" + +#import + +@implementation GroundOverlayViewController { + GMSGroundOverlay *overlay_; +} + +- (void)viewDidLoad { + [super viewDidLoad]; + + CLLocationCoordinate2D southWest = CLLocationCoordinate2DMake(40.712216, -74.22655); + CLLocationCoordinate2D northEast = CLLocationCoordinate2DMake(40.773941, -74.12544); + + GMSCoordinateBounds *overlayBounds = [[GMSCoordinateBounds alloc] initWithCoordinate:southWest + coordinate:northEast]; + + // Choose the midpoint of the coordinate to focus the camera on. + CLLocationCoordinate2D newark = GMSGeometryInterpolate(southWest, northEast, 0.5); + GMSCameraPosition *camera = [GMSCameraPosition cameraWithTarget:newark + zoom:12 + bearing:0 + viewingAngle:45]; + GMSMapView *mapView = [GMSMapView mapWithFrame:CGRectZero camera:camera]; + + // Add the ground overlay, centered in Newark, NJ + GMSGroundOverlay *groundOverlay = [[GMSGroundOverlay alloc] init]; + // Image from http://www.lib.utexas.edu/maps/historical/newark_nj_1922.jpg + groundOverlay.icon = [UIImage imageNamed:@"newark_nj_1922.jpg"]; + groundOverlay.position = newark; + groundOverlay.bounds = overlayBounds; + groundOverlay.map = mapView; + + self.view = mapView; +} + +@end diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/IndoorMuseumNavigationViewController.h b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/IndoorMuseumNavigationViewController.h new file mode 100644 index 0000000..1dc3756 --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/IndoorMuseumNavigationViewController.h @@ -0,0 +1,9 @@ +#import + +#import + +@interface IndoorMuseumNavigationViewController : UIViewController< + GMSMapViewDelegate, + GMSIndoorDisplayDelegate> + +@end diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/IndoorMuseumNavigationViewController.m b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/IndoorMuseumNavigationViewController.m new file mode 100644 index 0000000..ca393b6 --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/IndoorMuseumNavigationViewController.m @@ -0,0 +1,115 @@ +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +#import "SDKDemos/Samples/IndoorMuseumNavigationViewController.h" + +@implementation IndoorMuseumNavigationViewController { + GMSMapView *mapView_; + NSArray *exhibits_; // Array of JSON exhibit data. + NSDictionary *exhibit_; // The currently selected exhibit. Will be nil initially. + GMSMarker *marker_; + NSDictionary *levels_; // The levels dictionary is updated when a new building is selected, and + // contains mapping from localized level name to GMSIndoorLevel. +} + +- (void)viewDidLoad { + [super viewDidLoad]; + + GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:38.8879 + longitude:-77.0200 + zoom:17]; + mapView_ = [GMSMapView mapWithFrame:CGRectZero camera:camera]; + mapView_.settings.myLocationButton = NO; + mapView_.settings.indoorPicker = NO; + mapView_.delegate = self; + mapView_.indoorDisplay.delegate = self; + + self.view = mapView_; + + // Load the exhibits configuration from JSON + NSString *jsonPath = [[NSBundle mainBundle] pathForResource:@"museum-exhibits" ofType:@"json"]; + NSData *data = [NSData dataWithContentsOfFile:jsonPath]; + exhibits_ = [NSJSONSerialization JSONObjectWithData:data + options:kNilOptions + error:nil]; + + + UISegmentedControl *segmentedControl = [[UISegmentedControl alloc] init]; + [segmentedControl setTintColor:[UIColor colorWithRed:0.373f green:0.667f blue:0.882f alpha:1.0f]]; + + segmentedControl.translatesAutoresizingMaskIntoConstraints = NO; + [segmentedControl addTarget:self + action:@selector(exhibitSelected:) + forControlEvents:UIControlEventValueChanged]; + [self.view addSubview:segmentedControl]; + + for (NSDictionary *exhibit in exhibits_) { + [segmentedControl insertSegmentWithImage:[UIImage imageNamed:exhibit[@"key"]] + atIndex:[exhibits_ indexOfObject:exhibit] + animated:NO]; + } + + NSDictionary *views = NSDictionaryOfVariableBindings(segmentedControl); + + [self.view addConstraints:[NSLayoutConstraint + constraintsWithVisualFormat:@"[segmentedControl]-|" + options:kNilOptions + metrics:nil + views:views]]; + [self.view addConstraints:[NSLayoutConstraint + constraintsWithVisualFormat:@"V:[segmentedControl]-|" + options:kNilOptions + metrics:nil + views:views]]; + +} + +- (void)moveMarker { + CLLocationCoordinate2D loc = CLLocationCoordinate2DMake([exhibit_[@"lat"] doubleValue], + [exhibit_[@"lng"] doubleValue]); + if (marker_ == nil) { + marker_ = [GMSMarker markerWithPosition:loc]; + marker_.map = mapView_; + } else { + marker_.position = loc; + } + marker_.title = exhibit_[@"name"]; + [mapView_ animateToLocation:loc]; + [mapView_ animateToZoom:19]; +} + +- (void)exhibitSelected:(UISegmentedControl *)segmentedControl { + exhibit_ = exhibits_[[segmentedControl selectedSegmentIndex]]; + [self moveMarker]; +} + +#pragma mark - GMSMapViewDelegate + +- (void)mapView:(GMSMapView *)mapView idleAtCameraPosition:(GMSCameraPosition *)camera { + if (exhibit_ != nil) { + CLLocationCoordinate2D loc = CLLocationCoordinate2DMake([exhibit_[@"lat"] doubleValue], + [exhibit_[@"lng"] doubleValue]); + if ([mapView_.projection containsCoordinate:loc] && levels_ != nil) { + [mapView.indoorDisplay setActiveLevel:levels_[exhibit_[@"level"]]]; + } + } +} + +#pragma mark - GMSIndoorDisplayDelegate + +- (void)didChangeActiveBuilding:(GMSIndoorBuilding *)building { + if (building != nil) { + NSMutableDictionary *levels = [NSMutableDictionary dictionary]; + + for (GMSIndoorLevel *level in building.levels) { + [levels setObject:level forKey:level.shortName]; + } + + levels_ = [NSDictionary dictionaryWithDictionary:levels]; + } else { + levels_ = nil; + } +} + +@end diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/IndoorViewController.h b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/IndoorViewController.h new file mode 100644 index 0000000..95c10e1 --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/IndoorViewController.h @@ -0,0 +1,5 @@ +#import + +@interface IndoorViewController : UIViewController + +@end diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/IndoorViewController.m b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/IndoorViewController.m new file mode 100644 index 0000000..6d849e3 --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/IndoorViewController.m @@ -0,0 +1,26 @@ +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +#import "SDKDemos/Samples/IndoorViewController.h" + +#import + +@implementation IndoorViewController { + GMSMapView *mapView_; +} + +- (void)viewDidLoad { + [super viewDidLoad]; + GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:37.78318 + longitude:-122.403874 + zoom:18]; + + mapView_ = [GMSMapView mapWithFrame:CGRectZero camera:camera]; + mapView_.settings.myLocationButton = YES; + + self.view = mapView_; +} + + +@end diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/MapLayerViewController.h b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/MapLayerViewController.h new file mode 100644 index 0000000..6bc88e4 --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/MapLayerViewController.h @@ -0,0 +1,5 @@ +#import + +@interface MapLayerViewController : UIViewController + +@end diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/MapLayerViewController.m b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/MapLayerViewController.m new file mode 100644 index 0000000..40b31b0 --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/MapLayerViewController.m @@ -0,0 +1,79 @@ +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +#import "SDKDemos/Samples/MapLayerViewController.h" + +#import + +@implementation MapLayerViewController { + GMSMapView *mapView_; +} + +- (void)viewDidLoad { + [super viewDidLoad]; + GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:-37.81969 + longitude:144.966085 + zoom:4]; + mapView_ = [GMSMapView mapWithFrame:CGRectZero camera:camera]; + self.view = mapView_; + + dispatch_async(dispatch_get_main_queue(), ^{ + mapView_.myLocationEnabled = YES; + }); + + UIBarButtonItem *myLocationButton = + [[UIBarButtonItem alloc] initWithTitle:@"Fly to My Location" + style:UIBarButtonItemStylePlain + target:self + action:@selector(didTapMyLocation)]; + self.navigationItem.rightBarButtonItem = myLocationButton; + +} + +- (void)didTapMyLocation { + CLLocation *location = mapView_.myLocation; + if (!location || !CLLocationCoordinate2DIsValid(location.coordinate)) { + return; + } + + mapView_.layer.cameraLatitude = location.coordinate.latitude; + mapView_.layer.cameraLongitude = location.coordinate.longitude; + mapView_.layer.cameraBearing = 0.0; + + // Access the GMSMapLayer directly to modify the following properties with a + // specified timing function and duration. + + CAMediaTimingFunction *curve = + [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; + CABasicAnimation *animation; + + animation = [CABasicAnimation animationWithKeyPath:kGMSLayerCameraLatitudeKey]; + animation.duration = 2.0f; + animation.timingFunction = curve; + animation.toValue = @(location.coordinate.latitude); + [mapView_.layer addAnimation:animation forKey:kGMSLayerCameraLatitudeKey]; + + animation = [CABasicAnimation animationWithKeyPath:kGMSLayerCameraLongitudeKey]; + animation.duration = 2.0f; + animation.timingFunction = curve; + animation.toValue = @(location.coordinate.longitude); + [mapView_.layer addAnimation:animation forKey:kGMSLayerCameraLongitudeKey]; + + animation = [CABasicAnimation animationWithKeyPath:kGMSLayerCameraBearingKey]; + animation.duration = 2.0f; + animation.timingFunction = curve; + animation.toValue = @0.0; + [mapView_.layer addAnimation:animation forKey:kGMSLayerCameraBearingKey]; + + // Fly out to the minimum zoom and then zoom back to the current zoom! + CGFloat zoom = mapView_.camera.zoom; + NSArray *keyValues = @[@(zoom), @(kGMSMinZoomLevel), @(zoom)]; + CAKeyframeAnimation *keyFrameAnimation = + [CAKeyframeAnimation animationWithKeyPath:kGMSLayerCameraZoomLevelKey]; + keyFrameAnimation.duration = 2.0f; + keyFrameAnimation.values = keyValues; + [mapView_.layer addAnimation:keyFrameAnimation forKey:kGMSLayerCameraZoomLevelKey]; +} + +@end diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/MapTypesViewController.h b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/MapTypesViewController.h new file mode 100644 index 0000000..33f5b67 --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/MapTypesViewController.h @@ -0,0 +1,5 @@ +#import + +@interface MapTypesViewController : UIViewController + +@end diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/MapTypesViewController.m b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/MapTypesViewController.m new file mode 100644 index 0000000..6d256c6 --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/MapTypesViewController.m @@ -0,0 +1,60 @@ +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +#import "SDKDemos/Samples/MapTypesViewController.h" + +#import + +static NSString const * kNormalType = @"Normal"; +static NSString const * kSatelliteType = @"Satellite"; +static NSString const * kHybridType = @"Hybrid"; +static NSString const * kTerrainType = @"Terrain"; + +@implementation MapTypesViewController { + UISegmentedControl *switcher_; + GMSMapView *mapView_; +} + +- (void)viewDidLoad { + [super viewDidLoad]; + + GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:-33.868 + longitude:151.2086 + zoom:12]; + + mapView_ = [GMSMapView mapWithFrame:CGRectZero camera:camera]; + self.view = mapView_; + + // The possible different types to show. + NSArray *types = @[kNormalType, kSatelliteType, kHybridType, kTerrainType]; + + // Create a UISegmentedControl that is the navigationItem's titleView. + switcher_ = [[UISegmentedControl alloc] initWithItems:types]; + switcher_.autoresizingMask = UIViewAutoresizingFlexibleBottomMargin | + UIViewAutoresizingFlexibleWidth | + UIViewAutoresizingFlexibleBottomMargin; + switcher_.selectedSegmentIndex = 0; + self.navigationItem.titleView = switcher_; + + // Listen to touch events on the UISegmentedControl. + [switcher_ addTarget:self action:@selector(didChangeSwitcher) + forControlEvents:UIControlEventValueChanged]; +} + +- (void)didChangeSwitcher { + // Switch to the type clicked on. + NSString *title = + [switcher_ titleForSegmentAtIndex:switcher_.selectedSegmentIndex]; + if ([kNormalType isEqualToString:title]) { + mapView_.mapType = kGMSTypeNormal; + } else if ([kSatelliteType isEqualToString:title]) { + mapView_.mapType = kGMSTypeSatellite; + } else if ([kHybridType isEqualToString:title]) { + mapView_.mapType = kGMSTypeHybrid; + } else if ([kTerrainType isEqualToString:title]) { + mapView_.mapType = kGMSTypeTerrain; + } +} + +@end diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/MapZoomViewController.h b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/MapZoomViewController.h new file mode 100644 index 0000000..d610aa9 --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/MapZoomViewController.h @@ -0,0 +1,5 @@ +#import + +@interface MapZoomViewController : UIViewController + +@end diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/MapZoomViewController.m b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/MapZoomViewController.m new file mode 100644 index 0000000..2371f87 --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/MapZoomViewController.m @@ -0,0 +1,73 @@ +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +#import "SDKDemos/Samples/MapZoomViewController.h" + +#import + +@implementation MapZoomViewController { + GMSMapView *mapView_; + UITextView *zoomRangeView_; + NSUInteger nextMode_; +} + +- (void)viewDidLoad { + [super viewDidLoad]; + GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:-33.868 + longitude:151.2086 + zoom:6]; + mapView_ = [GMSMapView mapWithFrame:CGRectZero camera:camera]; + mapView_.settings.scrollGestures = NO; + self.view = mapView_; + + // Add a display for the current zoom range restriction. + zoomRangeView_ = [[UITextView alloc] init]; + zoomRangeView_.frame = + CGRectMake(0, 0, CGRectGetWidth(self.view.frame), 0); + zoomRangeView_.text = @""; + zoomRangeView_.textAlignment = NSTextAlignmentCenter; + zoomRangeView_.backgroundColor = [UIColor colorWithWhite:1.0 alpha:0.8f]; + zoomRangeView_.autoresizingMask = UIViewAutoresizingFlexibleWidth; + [self.view addSubview:zoomRangeView_]; + [zoomRangeView_ sizeToFit]; + [self didTapNext]; + + // Add a button toggling through modes. + self.navigationItem.rightBarButtonItem = + [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemPlay + target:self + action:@selector(didTapNext)]; +} + +- (void)didTapNext { + NSString *label = @""; + float minZoom = kGMSMinZoomLevel; + float maxZoom = kGMSMaxZoomLevel; + + switch (nextMode_) { + case 0: + label = @"Default"; + break; + case 1: + minZoom = 18; + label = @"Zoomed in"; + break; + case 2: + maxZoom = 8; + label = @"Zoomed out"; + break; + case 3: + minZoom = 10; + maxZoom = 11.5; + label = @"Small range"; + break; + } + nextMode_ = (nextMode_ + 1) % 4; + + [mapView_ setMinZoom:minZoom maxZoom:maxZoom]; + zoomRangeView_.text = + [NSString stringWithFormat:@"%@ (%.2f - %.2f)", label, mapView_.minZoom, mapView_.maxZoom]; +} + +@end diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/MarkerEventsViewController.h b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/MarkerEventsViewController.h new file mode 100644 index 0000000..414b293 --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/MarkerEventsViewController.h @@ -0,0 +1,7 @@ +#import + +#import + +@interface MarkerEventsViewController : UIViewController + +@end diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/MarkerEventsViewController.m b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/MarkerEventsViewController.m new file mode 100644 index 0000000..ad498c7 --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/MarkerEventsViewController.m @@ -0,0 +1,70 @@ +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +#import "SDKDemos/Samples/MarkerEventsViewController.h" + +#import + +#import + +@implementation MarkerEventsViewController { + GMSMapView *mapView_; + GMSMarker *melbourneMarker_; +} + +- (void)viewDidLoad { + [super viewDidLoad]; + GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:-37.81969 + longitude:144.966085 + zoom:4]; + mapView_ = [GMSMapView mapWithFrame:CGRectZero camera:camera]; + + GMSMarker *sydneyMarker = [[GMSMarker alloc] init]; + sydneyMarker.position = CLLocationCoordinate2DMake(-33.8683, 151.2086); + sydneyMarker.map = mapView_; + + melbourneMarker_ = [[GMSMarker alloc] init]; + melbourneMarker_.position = CLLocationCoordinate2DMake(-37.81969, 144.966085); + melbourneMarker_.map = mapView_; + + mapView_.delegate = self; + self.view = mapView_; +} + +#pragma mark - GMSMapViewDelegate + +- (UIView *)mapView:(GMSMapView *)mapView markerInfoWindow:(GMSMarker *)marker { + if (marker == melbourneMarker_) { + return [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"Icon"]]; + } + + return nil; +} + +- (BOOL)mapView:(GMSMapView *)mapView didTapMarker:(GMSMarker *)marker { + // Animate to the marker + [CATransaction begin]; + [CATransaction setAnimationDuration:3.f]; // 3 second animation + + GMSCameraPosition *camera = + [[GMSCameraPosition alloc] initWithTarget:marker.position + zoom:8 + bearing:50 + viewingAngle:60]; + [mapView animateToCameraPosition:camera]; + [CATransaction commit]; + + // Melbourne marker has a InfoWindow so return NO to allow markerInfoWindow to + // fire. Also check that the marker isn't already selected so that the + // InfoWindow doesn't close. + if (marker == melbourneMarker_ && + mapView.selectedMarker != melbourneMarker_) { + return NO; + } + + // The Tap has been handled so return YES + return YES; +} + +@end diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/MarkerInfoWindowViewController.h b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/MarkerInfoWindowViewController.h new file mode 100644 index 0000000..74c7953 --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/MarkerInfoWindowViewController.h @@ -0,0 +1,5 @@ +#import + +@interface MarkerInfoWindowViewController : UIViewController + +@end diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/MarkerInfoWindowViewController.m b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/MarkerInfoWindowViewController.m new file mode 100644 index 0000000..5f6c931 --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/MarkerInfoWindowViewController.m @@ -0,0 +1,73 @@ +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +#import "SDKDemos/Samples/MarkerInfoWindowViewController.h" + +#import + +@interface MarkerInfoWindowViewController () +@end + +@implementation MarkerInfoWindowViewController { + GMSMarker *_sydneyMarker; + GMSMarker *_melbourneMarker; + GMSMarker *_brisbaneMarker; + UIView *_contentView; +} + +- (void)viewDidLoad { + [super viewDidLoad]; + GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:-37.81969 + longitude:144.966085 + zoom:4]; + GMSMapView *mapView = [GMSMapView mapWithFrame:CGRectZero camera:camera]; + + + _sydneyMarker = [[GMSMarker alloc] init]; + _sydneyMarker.title = @"Sydney"; + _sydneyMarker.snippet = @"Population: 4,605,992"; + _sydneyMarker.position = CLLocationCoordinate2DMake(-33.8683, 151.2086); + _sydneyMarker.map = mapView; + NSLog(@"sydneyMarker: %@", _sydneyMarker); + + + _melbourneMarker.map = nil; + _melbourneMarker = [[GMSMarker alloc] init]; + _melbourneMarker.title = @"Melbourne"; + _melbourneMarker.snippet = @"Population: 4,169,103"; + _melbourneMarker.position = CLLocationCoordinate2DMake(-37.81969, 144.966085); + _melbourneMarker.map = mapView; + NSLog(@"melbourneMarker: %@", _melbourneMarker); + + _brisbaneMarker.map = nil; + _brisbaneMarker = [[GMSMarker alloc] init]; + _brisbaneMarker.title = @"Brisbane"; + _brisbaneMarker.snippet = @"Population: 2,189,878"; + _brisbaneMarker.position = CLLocationCoordinate2DMake(-27.4710107, 153.0234489); + _brisbaneMarker.map = mapView; + NSLog(@"brisbaneMarker: %@", _brisbaneMarker); + + _contentView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"aeroplane"]]; + + mapView.delegate = self; + self.view = mapView; +} + +#pragma mark GMSMapViewDelegate + +- (UIView *)mapView:(GMSMapView *)mapView markerInfoWindow:(GMSMarker *)marker { + if (marker == _sydneyMarker) { + return _contentView; + } + return nil; +} + +- (UIView *)mapView:(GMSMapView *)mapView markerInfoContents:(GMSMarker *)marker { + if (marker == _brisbaneMarker) { + return _contentView; + } + return nil; +} + +@end diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/MarkerLayerViewController.h b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/MarkerLayerViewController.h new file mode 100644 index 0000000..d40e364 --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/MarkerLayerViewController.h @@ -0,0 +1,7 @@ +#import + +#import + +@interface MarkerLayerViewController : UIViewController + +@end diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/MarkerLayerViewController.m b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/MarkerLayerViewController.m new file mode 100644 index 0000000..0bc8992 --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/MarkerLayerViewController.m @@ -0,0 +1,137 @@ +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +#import "SDKDemos/Samples/MarkerLayerViewController.h" + +#import + +@interface CoordsList : NSObject +@property(nonatomic, readonly, copy) GMSPath *path; +@property(nonatomic, readonly) NSUInteger target; + +- (id)initWithPath:(GMSPath *)path; + +- (CLLocationCoordinate2D)next; + +@end + +@implementation CoordsList + +- (id)initWithPath:(GMSPath *)path { + if ((self = [super init])) { + _path = [path copy]; + _target = 0; + } + return self; +} + +- (CLLocationCoordinate2D)next { + ++_target; + if (_target == [_path count]) { + _target = 0; + } + return [_path coordinateAtIndex:_target]; +} + +@end + +@implementation MarkerLayerViewController { + GMSMapView *mapView_; + GMSMarker *fadedMarker_; +} + +- (void)viewDidLoad { + [super viewDidLoad]; + mapView_ = [[GMSMapView alloc] init]; + mapView_.camera = [GMSCameraPosition cameraWithLatitude:50.6042 longitude:3.9599 zoom:5]; + mapView_.delegate = self; + self.view = mapView_; + + GMSMutablePath *coords; + GMSMarker *marker; + + // Create a plane that flies to several airports around western Europe. + coords = [GMSMutablePath path]; + [coords addLatitude:52.310683 longitude:4.765121]; + [coords addLatitude:51.471386 longitude:-0.457148]; + [coords addLatitude:49.01378 longitude:2.5542943]; + [coords addLatitude:50.036194 longitude:8.554519]; + marker = [GMSMarker markerWithPosition:[coords coordinateAtIndex:0]]; + marker.icon = [UIImage imageNamed:@"aeroplane"]; + marker.groundAnchor = CGPointMake(0.5f, 0.5f); + marker.flat = YES; + marker.map = mapView_; + marker.userData = [[CoordsList alloc] initWithPath:coords]; + [self animateToNextCoord:marker]; + + // Create a boat that moves around the Baltic Sea. + coords = [GMSMutablePath path]; + [coords addLatitude:57.598335 longitude:11.290512]; + [coords addLatitude:55.665193 longitude:10.741196]; + [coords addLatitude:55.065787 longitude:11.083488]; + [coords addLatitude:54.699234 longitude:10.863762]; + [coords addLatitude:54.482805 longitude:12.061272]; + [coords addLatitude:55.819802 longitude:16.148186]; // final point + [coords addLatitude:54.927142 longitude:16.455803]; // final point + [coords addLatitude:54.482805 longitude:12.061272]; // and back again + [coords addLatitude:54.699234 longitude:10.863762]; + [coords addLatitude:55.065787 longitude:11.083488]; + [coords addLatitude:55.665193 longitude:10.741196]; + marker = [GMSMarker markerWithPosition:[coords coordinateAtIndex:0]]; + marker.icon = [UIImage imageNamed:@"boat"]; + marker.map = mapView_; + marker.userData = [[CoordsList alloc] initWithPath:coords]; + [self animateToNextCoord:marker]; +} + +- (void)animateToNextCoord:(GMSMarker *)marker { + CoordsList *coords = marker.userData; + CLLocationCoordinate2D coord = [coords next]; + CLLocationCoordinate2D previous = marker.position; + + CLLocationDirection heading = GMSGeometryHeading(previous, coord); + CLLocationDistance distance = GMSGeometryDistance(previous, coord); + + // Use CATransaction to set a custom duration for this animation. By default, changes to the + // position are already animated, but with a very short default duration. When the animation is + // complete, trigger another animation step. + + [CATransaction begin]; + [CATransaction setAnimationDuration:(distance / (50 * 1000))]; // custom duration, 50km/sec + + __weak MarkerLayerViewController *weakSelf = self; + [CATransaction setCompletionBlock:^{ + [weakSelf animateToNextCoord:marker]; + }]; + + marker.position = coord; + + [CATransaction commit]; + + // If this marker is flat, implicitly trigger a change in rotation, which will finish quickly. + if (marker.flat) { + marker.rotation = heading; + } +} + +- (void)fadeMarker:(GMSMarker *)marker { + fadedMarker_.opacity = 1.0f; // reset previous faded marker + + // Fade this new marker. + fadedMarker_ = marker; + fadedMarker_.opacity = 0.5f; +} + +#pragma mark - GMSMapViewDelegate + +- (BOOL)mapView:(GMSMapView *)mapView didTapMarker:(GMSMarker *)marker { + [self fadeMarker:marker]; + return YES; +} + +- (void)mapView:(GMSMapView *)mapView didTapAtCoordinate:(CLLocationCoordinate2D)coordinate { + [self fadeMarker:nil]; +} + +@end diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/MarkersViewController.h b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/MarkersViewController.h new file mode 100644 index 0000000..f9eaeee --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/MarkersViewController.h @@ -0,0 +1,5 @@ +#import + +@interface MarkersViewController : UIViewController + +@end diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/MarkersViewController.m b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/MarkersViewController.m new file mode 100644 index 0000000..b00ec08 --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/MarkersViewController.m @@ -0,0 +1,63 @@ +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +#import "SDKDemos/Samples/MarkersViewController.h" + +#import + +@implementation MarkersViewController { + GMSMarker *_sydneyMarker; + GMSMarker *_melbourneMarker; +} + +- (void)viewDidLoad { + [super viewDidLoad]; + GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:-37.81969 + longitude:144.966085 + zoom:4]; + GMSMapView *mapView = [GMSMapView mapWithFrame:CGRectZero camera:camera]; + + _sydneyMarker = [[GMSMarker alloc] init]; + _sydneyMarker.title = @"Sydney"; + _sydneyMarker.snippet = @"Population: 4,605,992"; + _sydneyMarker.position = CLLocationCoordinate2DMake(-33.8683, 151.2086); + _sydneyMarker.flat = NO; + _sydneyMarker.rotation = 30.0; + NSLog(@"sydneyMarker: %@", _sydneyMarker); + + GMSMarker *australiaMarker = [[GMSMarker alloc] init]; + australiaMarker.title = @"Australia"; + australiaMarker.position = CLLocationCoordinate2DMake(-27.994401,140.07019); + australiaMarker.appearAnimation = kGMSMarkerAnimationPop; + australiaMarker.flat = YES; + australiaMarker.draggable = YES; + australiaMarker.groundAnchor = CGPointMake(0.5, 0.5); + australiaMarker.icon = [UIImage imageNamed:@"australia"]; + australiaMarker.map = mapView; + + // Set the marker in Sydney to be selected + mapView.selectedMarker = _sydneyMarker; + + self.view = mapView; + self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(didTapAdd)]; +} + +- (void)didTapAdd { + if (_sydneyMarker.map == nil) { + _sydneyMarker.map = (GMSMapView *)self.view; +// _sydneyMarker.rotation += 45.0; + } else { + _sydneyMarker.map = nil; + } + + _melbourneMarker.map = nil; + _melbourneMarker = [[GMSMarker alloc] init]; + _melbourneMarker.title = @"Melbourne"; + _melbourneMarker.snippet = @"Population: 4,169,103"; + _melbourneMarker.position = CLLocationCoordinate2DMake(-37.81969, 144.966085); + _melbourneMarker.map = (GMSMapView *)self.view; +} + + +@end diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/MyLocationViewController.h b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/MyLocationViewController.h new file mode 100644 index 0000000..a592024 --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/MyLocationViewController.h @@ -0,0 +1,5 @@ +#import + +@interface MyLocationViewController : UIViewController + +@end diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/MyLocationViewController.m b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/MyLocationViewController.m new file mode 100644 index 0000000..baff8da --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/MyLocationViewController.m @@ -0,0 +1,60 @@ +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +#import "SDKDemos/Samples/MyLocationViewController.h" + +#import + +@implementation MyLocationViewController { + GMSMapView *mapView_; + BOOL firstLocationUpdate_; +} + +- (void)viewDidLoad { + [super viewDidLoad]; + GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:-33.868 + longitude:151.2086 + zoom:12]; + + mapView_ = [GMSMapView mapWithFrame:CGRectZero camera:camera]; + mapView_.settings.compassButton = YES; + mapView_.settings.myLocationButton = YES; + + // Listen to the myLocation property of GMSMapView. + [mapView_ addObserver:self + forKeyPath:@"myLocation" + options:NSKeyValueObservingOptionNew + context:NULL]; + + self.view = mapView_; + + // Ask for My Location data after the map has already been added to the UI. + dispatch_async(dispatch_get_main_queue(), ^{ + mapView_.myLocationEnabled = YES; + }); +} + +- (void)dealloc { + [mapView_ removeObserver:self + forKeyPath:@"myLocation" + context:NULL]; +} + +#pragma mark - KVO updates + +- (void)observeValueForKeyPath:(NSString *)keyPath + ofObject:(id)object + change:(NSDictionary *)change + context:(void *)context { + if (!firstLocationUpdate_) { + // If the first location update has not yet been recieved, then jump to that + // location. + firstLocationUpdate_ = YES; + CLLocation *location = [change objectForKey:NSKeyValueChangeNewKey]; + mapView_.camera = [GMSCameraPosition cameraWithTarget:location.coordinate + zoom:14]; + } +} + +@end diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/PanoramaViewController.h b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/PanoramaViewController.h new file mode 100644 index 0000000..3d65447 --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/PanoramaViewController.h @@ -0,0 +1,5 @@ +#import + +@interface PanoramaViewController : UIViewController + +@end diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/PanoramaViewController.m b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/PanoramaViewController.m new file mode 100644 index 0000000..c4ce998 --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/PanoramaViewController.m @@ -0,0 +1,53 @@ +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +#import "SDKDemos/Samples/PanoramaViewController.h" + +#import + +static CLLocationCoordinate2D kPanoramaNear = {40.761388, -73.978133}; +static CLLocationCoordinate2D kMarkerAt = {40.761455, -73.977814}; + +@interface PanoramaViewController () +@end + +@implementation PanoramaViewController { + GMSPanoramaView *view_; + BOOL configured_; +} + +- (void)viewDidLoad { + [super viewDidLoad]; + + view_ = [GMSPanoramaView panoramaWithFrame:CGRectZero + nearCoordinate:kPanoramaNear]; + view_.backgroundColor = [UIColor grayColor]; + view_.delegate = self; + self.view = view_; +} + +#pragma mark - GMSPanoramaDelegate + +- (void)panoramaView:(GMSPanoramaView *)panoramaView + didMoveCamera:(GMSPanoramaCamera *)camera { + NSLog(@"Camera: (%f,%f,%f)", + camera.orientation.heading, camera.orientation.pitch, camera.zoom); +} + +- (void)panoramaView:(GMSPanoramaView *)view + didMoveToPanorama:(GMSPanorama *)panorama { + if (!configured_) { + GMSMarker *marker = [GMSMarker markerWithPosition:kMarkerAt]; + marker.icon = [GMSMarker markerImageWithColor:[UIColor purpleColor]]; + marker.panoramaView = view_; + + CLLocationDegrees heading = GMSGeometryHeading(kPanoramaNear, kMarkerAt); + view_.camera = + [GMSPanoramaCamera cameraWithHeading:heading pitch:0 zoom:1]; + + configured_ = YES; + } +} + +@end diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/PolygonsViewController.h b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/PolygonsViewController.h new file mode 100644 index 0000000..2a7cf41 --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/PolygonsViewController.h @@ -0,0 +1,7 @@ +#import + +#import + +@interface PolygonsViewController : UIViewController + +@end diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/PolygonsViewController.m b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/PolygonsViewController.m new file mode 100644 index 0000000..e3495ee --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/PolygonsViewController.m @@ -0,0 +1,246 @@ +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +#import "SDKDemos/Samples/PolygonsViewController.h" + +#import + +@implementation PolygonsViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:39.13006 + longitude:-77.508545 + zoom:4]; + GMSMapView *mapView = [GMSMapView mapWithFrame:CGRectZero camera:camera]; + mapView.delegate = self; // needed for didTapOverlay delegate method + + // Create the first polygon. + GMSPolygon *polygon = [[GMSPolygon alloc] init]; + polygon.path = [self pathOfNewYorkState]; + polygon.title = @"New York"; + polygon.fillColor = [UIColor colorWithRed:0.25 green:0 blue:0 alpha:0.2f]; + polygon.strokeColor = [UIColor blackColor]; + polygon.strokeWidth = 2; + polygon.tappable = YES; + polygon.map = mapView; + + // Copy the existing polygon and its settings and use it as a base for the + // second polygon. + polygon = [polygon copy]; + polygon.title = @"North Carolina"; + polygon.path = [self pathOfNorthCarolina]; + polygon.fillColor = [UIColor colorWithRed:0 green:0.25 blue:0 alpha:0.5]; + polygon.map = mapView; + + self.view = mapView; +} + +- (void)mapView:(GMSMapView *)mapView didTapOverlay:(GMSOverlay *)overlay { + // When a polygon is tapped, randomly change its fill color to a new hue. + if ([overlay isKindOfClass:[GMSPolygon class]]) { + GMSPolygon *polygon = (GMSPolygon *)overlay; + CGFloat hue = (((float)arc4random()/0x100000000)*1.0f); + polygon.fillColor = + [UIColor colorWithHue:hue saturation:1 brightness:1 alpha:0.5]; + } +} + +- (GMSPath *)pathOfNewYorkState { + GMSMutablePath *path = [GMSMutablePath path]; + [path addLatitude:42.5142 longitude:-79.7624]; + [path addLatitude:42.7783 longitude:-79.0672]; + [path addLatitude:42.8508 longitude:-78.9313]; + [path addLatitude:42.9061 longitude:-78.9024]; + [path addLatitude:42.9554 longitude:-78.9313]; + [path addLatitude:42.9584 longitude:-78.9656]; + [path addLatitude:42.9886 longitude:-79.0219]; + [path addLatitude:43.0568 longitude:-79.0027]; + [path addLatitude:43.0769 longitude:-79.0727]; + [path addLatitude:43.1220 longitude:-79.0713]; + [path addLatitude:43.1441 longitude:-79.0302]; + [path addLatitude:43.1801 longitude:-79.0576]; + [path addLatitude:43.2482 longitude:-79.0604]; + [path addLatitude:43.2812 longitude:-79.0837]; + [path addLatitude:43.4509 longitude:-79.2004]; + [path addLatitude:43.6311 longitude:-78.6909]; + [path addLatitude:43.6321 longitude:-76.7958]; + [path addLatitude:43.9987 longitude:-76.4978]; + [path addLatitude:44.0965 longitude:-76.4388]; + [path addLatitude:44.1349 longitude:-76.3536]; + [path addLatitude:44.1989 longitude:-76.3124]; + [path addLatitude:44.2049 longitude:-76.2437]; + [path addLatitude:44.2413 longitude:-76.1655]; + [path addLatitude:44.2973 longitude:-76.1353]; + [path addLatitude:44.3327 longitude:-76.0474]; + [path addLatitude:44.3553 longitude:-75.9856]; + [path addLatitude:44.3749 longitude:-75.9196]; + [path addLatitude:44.3994 longitude:-75.8730]; + [path addLatitude:44.4308 longitude:-75.8221]; + [path addLatitude:44.4740 longitude:-75.8098]; + [path addLatitude:44.5425 longitude:-75.7288]; + [path addLatitude:44.6647 longitude:-75.5585]; + [path addLatitude:44.7672 longitude:-75.4088]; + [path addLatitude:44.8101 longitude:-75.3442]; + [path addLatitude:44.8383 longitude:-75.3058]; + [path addLatitude:44.8676 longitude:-75.2399]; + [path addLatitude:44.9211 longitude:-75.1204]; + [path addLatitude:44.9609 longitude:-74.9995]; + [path addLatitude:44.9803 longitude:-74.9899]; + [path addLatitude:44.9852 longitude:-74.9103]; + [path addLatitude:45.0017 longitude:-74.8856]; + [path addLatitude:45.0153 longitude:-74.8306]; + [path addLatitude:45.0046 longitude:-74.7633]; + [path addLatitude:45.0027 longitude:-74.7070]; + [path addLatitude:45.0007 longitude:-74.5642]; + [path addLatitude:44.9920 longitude:-74.1467]; + [path addLatitude:45.0037 longitude:-73.7306]; + [path addLatitude:45.0085 longitude:-73.4203]; + [path addLatitude:45.0109 longitude:-73.3430]; + [path addLatitude:44.9874 longitude:-73.3547]; + [path addLatitude:44.9648 longitude:-73.3379]; + [path addLatitude:44.9160 longitude:-73.3396]; + [path addLatitude:44.8354 longitude:-73.3739]; + [path addLatitude:44.8013 longitude:-73.3324]; + [path addLatitude:44.7419 longitude:-73.3667]; + [path addLatitude:44.6139 longitude:-73.3873]; + [path addLatitude:44.5787 longitude:-73.3736]; + [path addLatitude:44.4916 longitude:-73.3049]; + [path addLatitude:44.4289 longitude:-73.2953]; + [path addLatitude:44.3513 longitude:-73.3365]; + [path addLatitude:44.2757 longitude:-73.3118]; + [path addLatitude:44.1980 longitude:-73.3818]; + [path addLatitude:44.1142 longitude:-73.4079]; + [path addLatitude:44.0511 longitude:-73.4367]; + [path addLatitude:44.0165 longitude:-73.4065]; + [path addLatitude:43.9375 longitude:-73.4079]; + [path addLatitude:43.8771 longitude:-73.3749]; + [path addLatitude:43.8167 longitude:-73.3914]; + [path addLatitude:43.7790 longitude:-73.3557]; + [path addLatitude:43.6460 longitude:-73.4244]; + [path addLatitude:43.5893 longitude:-73.4340]; + [path addLatitude:43.5655 longitude:-73.3969]; + [path addLatitude:43.6112 longitude:-73.3818]; + [path addLatitude:43.6271 longitude:-73.3049]; + [path addLatitude:43.5764 longitude:-73.3063]; + [path addLatitude:43.5675 longitude:-73.2582]; + [path addLatitude:43.5227 longitude:-73.2445]; + [path addLatitude:43.2582 longitude:-73.2582]; + [path addLatitude:42.9715 longitude:-73.2733]; + [path addLatitude:42.8004 longitude:-73.2898]; + [path addLatitude:42.7460 longitude:-73.2664]; + [path addLatitude:42.4630 longitude:-73.3708]; + [path addLatitude:42.0840 longitude:-73.5095]; + [path addLatitude:42.0218 longitude:-73.4903]; + [path addLatitude:41.8808 longitude:-73.4999]; + [path addLatitude:41.2953 longitude:-73.5535]; + [path addLatitude:41.2128 longitude:-73.4834]; + [path addLatitude:41.1011 longitude:-73.7275]; + [path addLatitude:41.0237 longitude:-73.6644]; + [path addLatitude:40.9851 longitude:-73.6578]; + [path addLatitude:40.9509 longitude:-73.6132]; + [path addLatitude:41.1869 longitude:-72.4823]; + [path addLatitude:41.2551 longitude:-72.0950]; + [path addLatitude:41.3005 longitude:-71.9714]; + [path addLatitude:41.3108 longitude:-71.9193]; + [path addLatitude:41.1838 longitude:-71.7915]; + [path addLatitude:41.1249 longitude:-71.7929]; + [path addLatitude:41.0462 longitude:-71.7517]; + [path addLatitude:40.6306 longitude:-72.9465]; + [path addLatitude:40.5368 longitude:-73.4628]; + [path addLatitude:40.4887 longitude:-73.8885]; + [path addLatitude:40.5232 longitude:-73.9490]; + [path addLatitude:40.4772 longitude:-74.2271]; + [path addLatitude:40.4861 longitude:-74.2532]; + [path addLatitude:40.6468 longitude:-74.1866]; + [path addLatitude:40.6556 longitude:-74.0547]; + [path addLatitude:40.7618 longitude:-74.0156]; + [path addLatitude:40.8699 longitude:-73.9421]; + [path addLatitude:40.9980 longitude:-73.8934]; + [path addLatitude:41.0343 longitude:-73.9854]; + [path addLatitude:41.3268 longitude:-74.6274]; + [path addLatitude:41.3583 longitude:-74.7084]; + [path addLatitude:41.3811 longitude:-74.7101]; + [path addLatitude:41.4386 longitude:-74.8265]; + [path addLatitude:41.5075 longitude:-74.9913]; + [path addLatitude:41.6000 longitude:-75.0668]; + [path addLatitude:41.6719 longitude:-75.0366]; + [path addLatitude:41.7672 longitude:-75.0545]; + [path addLatitude:41.8808 longitude:-75.1945]; + [path addLatitude:42.0013 longitude:-75.3552]; + [path addLatitude:42.0003 longitude:-75.4266]; + [path addLatitude:42.0013 longitude:-77.0306]; + [path addLatitude:41.9993 longitude:-79.7250]; + [path addLatitude:42.0003 longitude:-79.7621]; + [path addLatitude:42.1827 longitude:-79.7621]; + [path addLatitude:42.5146 longitude:-79.7621]; + return path; +} + +- (GMSPath *)pathOfNorthCarolina { + GMSMutablePath *path = [GMSMutablePath path]; + [path addLatitude:33.7963 longitude:-78.4850]; + [path addLatitude:34.8037 longitude:-79.6742]; + [path addLatitude:34.8206 longitude:-80.8003]; + [path addLatitude:34.9377 longitude:-80.7880]; + [path addLatitude:35.1019 longitude:-80.9377]; + [path addLatitude:35.0356 longitude:-81.0379]; + [path addLatitude:35.1457 longitude:-81.0324]; + [path addLatitude:35.1660 longitude:-81.3867]; + [path addLatitude:35.1985 longitude:-82.2739]; + [path addLatitude:35.2041 longitude:-82.3933]; + [path addLatitude:35.0637 longitude:-82.7765]; + [path addLatitude:35.0817 longitude:-82.7861]; + [path addLatitude:34.9996 longitude:-83.1075]; + [path addLatitude:34.9918 longitude:-83.6183]; + [path addLatitude:34.9918 longitude:-84.3201]; + [path addLatitude:35.2131 longitude:-84.2885]; + [path addLatitude:35.2680 longitude:-84.2226]; + [path addLatitude:35.2310 longitude:-84.1113]; + [path addLatitude:35.2815 longitude:-84.0454]; + [path addLatitude:35.4058 longitude:-84.0248]; + [path addLatitude:35.4719 longitude:-83.9424]; + [path addLatitude:35.5166 longitude:-83.8559]; + [path addLatitude:35.5512 longitude:-83.6938]; + [path addLatitude:35.5680 longitude:-83.5181]; + [path addLatitude:35.6327 longitude:-83.3849]; + [path addLatitude:35.7142 longitude:-83.2475]; + [path addLatitude:35.7799 longitude:-82.9962]; + [path addLatitude:35.8445 longitude:-82.9276]; + [path addLatitude:35.9224 longitude:-82.8191]; + [path addLatitude:35.9958 longitude:-82.7710]; + [path addLatitude:36.0613 longitude:-82.6419]; + [path addLatitude:35.9702 longitude:-82.6103]; + [path addLatitude:35.9547 longitude:-82.5677]; + [path addLatitude:36.0236 longitude:-82.4730]; + [path addLatitude:36.0669 longitude:-82.4194]; + [path addLatitude:36.1168 longitude:-82.3535]; + [path addLatitude:36.1345 longitude:-82.2862]; + [path addLatitude:36.1467 longitude:-82.1461]; + [path addLatitude:36.1035 longitude:-82.1228]; + [path addLatitude:36.1268 longitude:-82.0267]; + [path addLatitude:36.2797 longitude:-81.9360]; + [path addLatitude:36.3527 longitude:-81.7987]; + [path addLatitude:36.3361 longitude:-81.7081]; + [path addLatitude:36.5880 longitude:-81.6724]; + [path addLatitude:36.5659 longitude:-80.7234]; + [path addLatitude:36.5438 longitude:-80.2977]; + [path addLatitude:36.5449 longitude:-79.6729]; + [path addLatitude:36.5449 longitude:-77.2559]; + [path addLatitude:36.5505 longitude:-75.7562]; + [path addLatitude:36.3129 longitude:-75.7068]; + [path addLatitude:35.7131 longitude:-75.4129]; + [path addLatitude:35.2041 longitude:-75.4720]; + [path addLatitude:34.9794 longitude:-76.0748]; + [path addLatitude:34.5258 longitude:-76.4951]; + [path addLatitude:34.5880 longitude:-76.8109]; + [path addLatitude:34.5314 longitude:-77.1378]; + [path addLatitude:34.3910 longitude:-77.4481]; + [path addLatitude:34.0481 longitude:-77.7983]; + [path addLatitude:33.7666 longitude:-77.9260]; + [path addLatitude:33.7963 longitude:-78.4863]; + return path; +} + +@end diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/PolylinesViewController.h b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/PolylinesViewController.h new file mode 100644 index 0000000..56a9d37 --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/PolylinesViewController.h @@ -0,0 +1,7 @@ +#import + +#import + +@interface PolylinesViewController : UIViewController + +@end diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/PolylinesViewController.m b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/PolylinesViewController.m new file mode 100644 index 0000000..518d796 --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/PolylinesViewController.m @@ -0,0 +1,111 @@ +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +#import "SDKDemos/Samples/PolylinesViewController.h" + +#import + +@interface GMSPolyline (length) + +@property(nonatomic, readonly) double length; + +@end + +@implementation GMSPolyline (length) + +- (double)length { + GMSLengthKind kind = [self geodesic] ? kGMSLengthGeodesic : kGMSLengthRhumb; + return [[self path] lengthOfKind:kind]; +} + +@end + +static CLLocationCoordinate2D kSydneyAustralia = {-33.866901, 151.195988}; +static CLLocationCoordinate2D kHawaiiUSA = {21.291982, -157.821856}; +static CLLocationCoordinate2D kFiji = {-18, 179}; +static CLLocationCoordinate2D kMountainViewUSA = {37.423802, -122.091859}; +static CLLocationCoordinate2D kLimaPeru = {-12, -77}; +static bool kAnimate = true; + +@implementation PolylinesViewController { + NSArray *_styles; + NSArray *_lengths; + NSArray *_polys; + double _pos, _step; + GMSMapView *_mapView; +} + +- (void)tick { + for (GMSPolyline *poly in _polys) { + poly.spans = + GMSStyleSpansOffset(poly.path, _styles, _lengths, kGMSLengthGeodesic, _pos); + } + _pos -= _step; + if (kAnimate) { + __weak id weakSelf = self; + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC / 10), + dispatch_get_main_queue(), + ^{ [weakSelf tick]; }); + } +} + +- (void)initLines { + if (!_polys) { + NSMutableArray *polys = [NSMutableArray array]; + GMSMutablePath *path = [GMSMutablePath path]; + [path addCoordinate:kSydneyAustralia]; + [path addCoordinate:kFiji]; + [path addCoordinate:kHawaiiUSA]; + [path addCoordinate:kMountainViewUSA]; + [path addCoordinate:kLimaPeru]; + [path addCoordinate:kSydneyAustralia]; + path = [path pathOffsetByLatitude:-30 longitude:0]; + _lengths = @[@([path lengthOfKind:kGMSLengthGeodesic] / 21)]; + for (int i = 0; i < 30; ++i) { + GMSPolyline *poly = [[GMSPolyline alloc] init]; + poly.path = [path pathOffsetByLatitude:(i * 1.5) longitude:0]; + poly.strokeWidth = 8; + poly.geodesic = YES; + poly.map = _mapView; + [polys addObject:poly]; + } + _polys = polys; + } +} + +- (void)mapView:(GMSMapView *)mapView + didTapAtCoordinate:(CLLocationCoordinate2D)coordinate { + [self initLines]; + [self tick]; +} + +- (void)viewDidLoad { + [super viewDidLoad]; + GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:-30 + longitude:-175 + zoom:3]; + GMSMapView *mapView = [GMSMapView mapWithFrame:CGRectZero camera:camera]; + mapView.accessibilityElementsHidden = YES; + self.view = mapView; + mapView.delegate = self; + _mapView = mapView; + + CGFloat alpha = 1; + UIColor *green = [UIColor colorWithRed:0 green:1 blue: 0 alpha:alpha]; + UIColor *greenTransp = [UIColor colorWithRed:0 green:1 blue: 0 alpha:0]; + UIColor *red = [UIColor colorWithRed:1 green:0 blue: 0 alpha:alpha]; + UIColor *redTransp = [UIColor colorWithRed:1 green:0 blue: 0 alpha:0]; + GMSStrokeStyle *grad1 = [GMSStrokeStyle gradientFromColor:green toColor:greenTransp]; + GMSStrokeStyle *grad2 = [GMSStrokeStyle gradientFromColor:redTransp toColor:red]; + _styles = @[ + grad1, + grad2, + [GMSStrokeStyle solidColor:[UIColor colorWithWhite:0 alpha:0]], + ]; + _step = 50000; + [self initLines]; + [self tick]; +} + +@end diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/Samples.h b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/Samples.h new file mode 100644 index 0000000..fdb0b1f --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/Samples.h @@ -0,0 +1,9 @@ +#import + +@interface Samples : NSObject ++ (NSArray *)loadSections; ++ (NSArray *)loadDemos; ++ (NSDictionary *)newDemo:(Class) class + withTitle:(NSString *)title + andDescription:(NSString *)description; +@end diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/Samples.m b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/Samples.m new file mode 100644 index 0000000..9b8ab4a --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/Samples.m @@ -0,0 +1,161 @@ +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +#import "SDKDemos/Samples/Samples.h" + +// Map Demos +#import "SDKDemos/Samples/BasicMapViewController.h" +#import "SDKDemos/Samples/CustomIndoorViewController.h" +#import "SDKDemos/Samples/DoubleMapViewController.h" +#import "SDKDemos/Samples/GestureControlViewController.h" +#import "SDKDemos/Samples/IndoorMuseumNavigationViewController.h" +#import "SDKDemos/Samples/IndoorViewController.h" +#import "SDKDemos/Samples/MapTypesViewController.h" +#import "SDKDemos/Samples/MapZoomViewController.h" +#import "SDKDemos/Samples/MyLocationViewController.h" +#import "SDKDemos/Samples/TrafficMapViewController.h" +#import "SDKDemos/Samples/VisibleRegionViewController.h" + +// Panorama Demos +#import "SDKDemos/Samples/FixedPanoramaViewController.h" +#import "SDKDemos/Samples/PanoramaViewController.h" + +// Overlay Demos +#import "SDKDemos/Samples/AnimatedCurrentLocationViewController.h" +#import "SDKDemos/Samples/CustomMarkersViewController.h" +#import "SDKDemos/Samples/GradientPolylinesViewController.h" +#import "SDKDemos/Samples/GroundOverlayViewController.h" +#import "SDKDemos/Samples/MarkerEventsViewController.h" +#import "SDKDemos/Samples/MarkerInfoWindowViewController.h" +#import "SDKDemos/Samples/MarkerLayerViewController.h" +#import "SDKDemos/Samples/MarkersViewController.h" +#import "SDKDemos/Samples/PolygonsViewController.h" +#import "SDKDemos/Samples/PolylinesViewController.h" +#import "SDKDemos/Samples/TileLayerViewController.h" + +// Camera Demos +#import "SDKDemos/Samples/CameraViewController.h" +#import "SDKDemos/Samples/FitBoundsViewController.h" +#import "SDKDemos/Samples/MapLayerViewController.h" + +// Services +#import "SDKDemos/Samples/GeocoderViewController.h" +#import "SDKDemos/Samples/StructuredGeocoderViewController.h" + +@implementation Samples + ++ (NSArray *)loadSections { + return @[ @"Map", @"Panorama", @"Overlays", @"Camera", @"Services" ]; +} + ++ (NSArray *)loadDemos { + NSArray *mapDemos = + @[[self newDemo:[BasicMapViewController class] + withTitle:@"Basic Map" + andDescription:nil], + [self newDemo:[MapTypesViewController class] + withTitle:@"Map Types" + andDescription:nil], + [self newDemo:[TrafficMapViewController class] + withTitle:@"Traffic Layer" + andDescription:nil], + [self newDemo:[MyLocationViewController class] + withTitle:@"My Location" + andDescription:nil], + [self newDemo:[IndoorViewController class] + withTitle:@"Indoor" + andDescription:nil], + [self newDemo:[CustomIndoorViewController class] + withTitle:@"Indoor with Custom Level Select" + andDescription:nil], + [self newDemo:[IndoorMuseumNavigationViewController class] + withTitle:@"Indoor Museum Navigator" + andDescription:nil], + [self newDemo:[GestureControlViewController class] + withTitle:@"Gesture Control" + andDescription:nil], + [self newDemo:[DoubleMapViewController class] + withTitle:@"Two Maps" + andDescription:nil], + [self newDemo:[VisibleRegionViewController class] + withTitle:@"Visible Regions" + andDescription:nil], + [self newDemo:[MapZoomViewController class] + withTitle:@"Min/Max Zoom" + andDescription:nil], + ]; + + NSArray *panoramaDemos = + @[[self newDemo:[PanoramaViewController class] + withTitle:@"Street View" + andDescription:nil], + [self newDemo:[FixedPanoramaViewController class] + withTitle:@"Fixed Street View" + andDescription:nil]]; + + NSArray *overlayDemos = + @[[self newDemo:[MarkersViewController class] + withTitle:@"Markers" + andDescription:nil], + [self newDemo:[CustomMarkersViewController class] + withTitle:@"Custom Markers" + andDescription:nil], + [self newDemo:[MarkerEventsViewController class] + withTitle:@"Marker Events" + andDescription:nil], + [self newDemo:[MarkerLayerViewController class] + withTitle:@"Marker Layer" + andDescription:nil], + [self newDemo:[MarkerInfoWindowViewController class] + withTitle:@"Custom Info Windows" + andDescription:nil], + [self newDemo:[PolygonsViewController class] + withTitle:@"Polygons" + andDescription:nil], + [self newDemo:[PolylinesViewController class] + withTitle:@"Polylines" + andDescription:nil], + [self newDemo:[GroundOverlayViewController class] + withTitle:@"Ground Overlays" + andDescription:nil], + [self newDemo:[TileLayerViewController class] + withTitle:@"Tile Layers" + andDescription:nil], + [self newDemo:[AnimatedCurrentLocationViewController class] + withTitle:@"Animated Current Location" + andDescription:nil], + [self newDemo:[GradientPolylinesViewController class] + withTitle:@"Gradient Polylines" + andDescription:nil]]; + + NSArray *cameraDemos = + @[[self newDemo:[FitBoundsViewController class] + withTitle:@"Fit Bounds" + andDescription:nil], + [self newDemo:[CameraViewController class] + withTitle:@"Camera Animation" + andDescription:nil], + [self newDemo:[MapLayerViewController class] + withTitle:@"Map Layer" + andDescription:nil]]; + + NSArray *servicesDemos = + @[[self newDemo:[GeocoderViewController class] + withTitle:@"Geocoder" + andDescription:nil], + [self newDemo:[StructuredGeocoderViewController class] + withTitle:@"Structured Geocoder" + andDescription:nil], + ]; + + return @[mapDemos, panoramaDemos, overlayDemos, cameraDemos, servicesDemos]; +} + ++ (NSDictionary *)newDemo:(Class) class + withTitle:(NSString *)title + andDescription:(NSString *)description { + return [[NSDictionary alloc] initWithObjectsAndKeys:class, @"controller", + title, @"title", description, @"description", nil]; +} +@end diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/StructuredGeocoderViewController.h b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/StructuredGeocoderViewController.h new file mode 100644 index 0000000..bc852a8 --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/StructuredGeocoderViewController.h @@ -0,0 +1,5 @@ +#import + +@interface StructuredGeocoderViewController : UIViewController + +@end diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/StructuredGeocoderViewController.m b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/StructuredGeocoderViewController.m new file mode 100644 index 0000000..ca66c61 --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/StructuredGeocoderViewController.m @@ -0,0 +1,77 @@ +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +#import "SDKDemos/Samples/StructuredGeocoderViewController.h" + +#import + +@interface StructuredGeocoderViewController () + +@end + +@implementation StructuredGeocoderViewController { + GMSMapView *_mapView; + GMSGeocoder *_geocoder; +} + +- (void)viewDidLoad { + [super viewDidLoad]; + GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:-33.868 + longitude:151.2086 + zoom:12]; + + _mapView = [GMSMapView mapWithFrame:CGRectZero camera:camera]; + _mapView.delegate = self; + + _geocoder = [[GMSGeocoder alloc] init]; + + self.view = _mapView; +} + +#pragma mark - GMSMapViewDelegate + +- (void)mapView:(GMSMapView *)mapView + didLongPressAtCoordinate:(CLLocationCoordinate2D)coordinate { + // On a long press, reverse geocode this location. + GMSReverseGeocodeCallback handler = ^(GMSReverseGeocodeResponse *response, NSError *error) { + GMSAddress *address = response.firstResult; + if (address) { + NSLog(@"Geocoder result: %@", address); + + GMSMarker *marker = [GMSMarker markerWithPosition:address.coordinate]; + + marker.title = address.thoroughfare; + + NSMutableString *snippet = [[NSMutableString alloc] init]; + if (address.subLocality != NULL) { + [snippet appendString:[NSString stringWithFormat:@"subLocality: %@\n", + address.subLocality]]; + } + if (address.locality != NULL) { + [snippet appendString:[NSString stringWithFormat:@"locality: %@\n", + address.locality]]; + } + if (address.administrativeArea != NULL) { + [snippet appendString:[NSString stringWithFormat:@"administrativeArea: %@\n", + address.administrativeArea]]; + } + if (address.country != NULL) { + [snippet appendString:[NSString stringWithFormat:@"country: %@\n", + address.country]]; + } + + marker.snippet = snippet; + + marker.appearAnimation = kGMSMarkerAnimationPop; + mapView.selectedMarker = marker; + marker.map = _mapView; + } else { + NSLog(@"Could not reverse geocode point (%f,%f): %@", + coordinate.latitude, coordinate.longitude, error); + } + }; + [_geocoder reverseGeocodeCoordinate:coordinate completionHandler:handler]; +} + +@end diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/TileLayerViewController.h b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/TileLayerViewController.h new file mode 100644 index 0000000..e330a66 --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/TileLayerViewController.h @@ -0,0 +1,5 @@ +#import + +@interface TileLayerViewController : UIViewController + +@end diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/TileLayerViewController.m b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/TileLayerViewController.m new file mode 100644 index 0000000..d23788e --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/TileLayerViewController.m @@ -0,0 +1,63 @@ +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +#import "SDKDemos/Samples/TileLayerViewController.h" + +#import + +@implementation TileLayerViewController { + UISegmentedControl *_switcher; + GMSMapView *_mapView; + GMSTileLayer *_tileLayer; + NSInteger _floor; +} + +- (void)viewDidLoad { + [super viewDidLoad]; + GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:37.78318 + longitude:-122.403874 + zoom:18]; + + _mapView = [GMSMapView mapWithFrame:CGRectZero camera:camera]; + _mapView.buildingsEnabled = NO; + _mapView.indoorEnabled = NO; + self.view = _mapView; + + // The possible floors that might be shown. + NSArray *types = @[ @"1", @"2", @"3" ]; + + // Create a UISegmentedControl that is the navigationItem's titleView. + _switcher = [[UISegmentedControl alloc] initWithItems:types]; + _switcher.selectedSegmentIndex = 0; + _switcher.autoresizingMask = UIViewAutoresizingFlexibleWidth; + _switcher.frame = + CGRectMake(0, 0, 300, _switcher.frame.size.height); + self.navigationItem.titleView = _switcher; + + // Listen to touch events on the UISegmentedControl, force initial update. + [_switcher addTarget:self action:@selector(didChangeSwitcher) + forControlEvents:UIControlEventValueChanged]; + [self didChangeSwitcher]; +} + +- (void)didChangeSwitcher { + NSString *title = + [_switcher titleForSegmentAtIndex:_switcher.selectedSegmentIndex]; + NSInteger floor = [title integerValue]; + if (_floor != floor) { + // Clear existing tileLayer, if any. + _tileLayer.map = nil; + + // Create a new GMSTileLayer with the new floor choice. + GMSTileURLConstructor urls = ^(NSUInteger x, NSUInteger y, NSUInteger zoom) { + NSString *url = [NSString stringWithFormat:@"http://www.gstatic.com/io2010maps/tiles/9/L%zd_%tu_%tu_%tu.png", floor, zoom, x, y]; + return [NSURL URLWithString:url]; + }; + _tileLayer = [GMSURLTileLayer tileLayerWithURLConstructor:urls]; + _tileLayer.map = _mapView; + _floor = floor; + } +} + +@end diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/TrafficMapViewController.h b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/TrafficMapViewController.h new file mode 100644 index 0000000..f7c69f2 --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/TrafficMapViewController.h @@ -0,0 +1,5 @@ +#import + +@interface TrafficMapViewController : UIViewController + +@end diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/TrafficMapViewController.m b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/TrafficMapViewController.m new file mode 100644 index 0000000..9ee26dd --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/TrafficMapViewController.m @@ -0,0 +1,22 @@ +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +#import "SDKDemos/Samples/TrafficMapViewController.h" + +#import + +@implementation TrafficMapViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:-33.868 + longitude:151.2086 + zoom:12]; + + GMSMapView *mapView = [GMSMapView mapWithFrame:CGRectZero camera:camera]; + mapView.trafficEnabled = YES; + self.view = mapView; +} + +@end diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/VisibleRegionViewController.h b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/VisibleRegionViewController.h new file mode 100644 index 0000000..d7747c4 --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/VisibleRegionViewController.h @@ -0,0 +1,5 @@ +#import + +@interface VisibleRegionViewController : UIViewController + +@end diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/VisibleRegionViewController.m b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/VisibleRegionViewController.m new file mode 100644 index 0000000..e14dddd --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/Samples/VisibleRegionViewController.m @@ -0,0 +1,60 @@ +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +#import "SDKDemos/Samples/VisibleRegionViewController.h" + +#import + +static CGFloat kOverlayHeight = 140.0f; + +@implementation VisibleRegionViewController { + GMSMapView *_mapView; + UIView *_overlay; + UIBarButtonItem *_flyInButton; +} + +- (void)viewDidLoad { + [super viewDidLoad]; + GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:-37.81969 + longitude:144.966085 + zoom:4]; + _mapView = [GMSMapView mapWithFrame:CGRectZero camera:camera]; + + // Enable my location button to show more UI components updating. + _mapView.settings.myLocationButton = YES; + _mapView.myLocationEnabled = YES; + _mapView.padding = UIEdgeInsetsMake(0, 0, kOverlayHeight, 0); + self.view = _mapView; + + // Create a button that, when pressed, causes an overlaying view to fly-in/out. + _flyInButton = [[UIBarButtonItem alloc] initWithTitle:@"Toggle Overlay" + style:UIBarButtonItemStylePlain + target:self + action:@selector(didTapFlyIn)]; + self.navigationItem.rightBarButtonItem = _flyInButton; + + CGRect overlayFrame = CGRectMake(0, -kOverlayHeight, 0, kOverlayHeight); + _overlay = [[UIView alloc] initWithFrame:overlayFrame]; + _overlay.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleWidth; + + _overlay.backgroundColor = [UIColor colorWithHue:0.0 saturation:1.0 brightness:1.0 alpha:0.5]; + [self.view addSubview:_overlay]; +} + +- (void)didTapFlyIn { + UIEdgeInsets padding = _mapView.padding; + + [UIView animateWithDuration:2.0 animations:^{ + CGSize size = self.view.bounds.size; + if (padding.bottom == 0.0f) { + _overlay.frame = CGRectMake(0, size.height - kOverlayHeight, size.width, kOverlayHeight); + _mapView.padding = UIEdgeInsetsMake(0, 0, kOverlayHeight, 0); + } else { + _overlay.frame = CGRectMake(0, _mapView.bounds.size.height, size.width, 0); + _mapView.padding = UIEdgeInsetsZero; + } + }]; +} + +@end diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/iTunesArtwork-1024.png b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/iTunesArtwork-1024.png new file mode 100644 index 0000000..eff1c1f Binary files /dev/null and b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/iTunesArtwork-1024.png differ diff --git a/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/main.m b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/main.m new file mode 100644 index 0000000..d0d2818 --- /dev/null +++ b/Pods/GoogleMaps/GoogleMapsSDKDemos/SDKDemos/main.m @@ -0,0 +1,13 @@ +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +#import + +#import "SDKDemos/SDKDemoAppDelegate.h" + +int main(int argc, char *argv[]) { + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([SDKDemoAppDelegate class])); + } +} diff --git a/Pods/Headers/Private/AFNetworking/AFHTTPClient.h b/Pods/Headers/Private/AFNetworking/AFHTTPClient.h new file mode 120000 index 0000000..aee081b --- /dev/null +++ b/Pods/Headers/Private/AFNetworking/AFHTTPClient.h @@ -0,0 +1 @@ +../../../AFNetworking/AFNetworking/AFHTTPClient.h \ No newline at end of file diff --git a/Pods/Headers/Private/AFNetworking/AFHTTPRequestOperation.h b/Pods/Headers/Private/AFNetworking/AFHTTPRequestOperation.h new file mode 120000 index 0000000..ac762c8 --- /dev/null +++ b/Pods/Headers/Private/AFNetworking/AFHTTPRequestOperation.h @@ -0,0 +1 @@ +../../../AFNetworking/AFNetworking/AFHTTPRequestOperation.h \ No newline at end of file diff --git a/Pods/Headers/Private/AFNetworking/AFImageRequestOperation.h b/Pods/Headers/Private/AFNetworking/AFImageRequestOperation.h new file mode 120000 index 0000000..c1fccfd --- /dev/null +++ b/Pods/Headers/Private/AFNetworking/AFImageRequestOperation.h @@ -0,0 +1 @@ +../../../AFNetworking/AFNetworking/AFImageRequestOperation.h \ No newline at end of file diff --git a/Pods/Headers/Private/AFNetworking/AFJSONRequestOperation.h b/Pods/Headers/Private/AFNetworking/AFJSONRequestOperation.h new file mode 120000 index 0000000..9f2188e --- /dev/null +++ b/Pods/Headers/Private/AFNetworking/AFJSONRequestOperation.h @@ -0,0 +1 @@ +../../../AFNetworking/AFNetworking/AFJSONRequestOperation.h \ No newline at end of file diff --git a/Pods/Headers/Private/AFNetworking/AFNetworkActivityIndicatorManager.h b/Pods/Headers/Private/AFNetworking/AFNetworkActivityIndicatorManager.h new file mode 120000 index 0000000..f454e54 --- /dev/null +++ b/Pods/Headers/Private/AFNetworking/AFNetworkActivityIndicatorManager.h @@ -0,0 +1 @@ +../../../AFNetworking/AFNetworking/AFNetworkActivityIndicatorManager.h \ No newline at end of file diff --git a/Pods/Headers/Private/AFNetworking/AFNetworking.h b/Pods/Headers/Private/AFNetworking/AFNetworking.h new file mode 120000 index 0000000..a5a38da --- /dev/null +++ b/Pods/Headers/Private/AFNetworking/AFNetworking.h @@ -0,0 +1 @@ +../../../AFNetworking/AFNetworking/AFNetworking.h \ No newline at end of file diff --git a/Pods/Headers/Private/AFNetworking/AFPropertyListRequestOperation.h b/Pods/Headers/Private/AFNetworking/AFPropertyListRequestOperation.h new file mode 120000 index 0000000..4b04bd2 --- /dev/null +++ b/Pods/Headers/Private/AFNetworking/AFPropertyListRequestOperation.h @@ -0,0 +1 @@ +../../../AFNetworking/AFNetworking/AFPropertyListRequestOperation.h \ No newline at end of file diff --git a/Pods/Headers/Private/AFNetworking/AFURLConnectionOperation.h b/Pods/Headers/Private/AFNetworking/AFURLConnectionOperation.h new file mode 120000 index 0000000..d9b35fb --- /dev/null +++ b/Pods/Headers/Private/AFNetworking/AFURLConnectionOperation.h @@ -0,0 +1 @@ +../../../AFNetworking/AFNetworking/AFURLConnectionOperation.h \ No newline at end of file diff --git a/Pods/Headers/Private/AFNetworking/AFXMLRequestOperation.h b/Pods/Headers/Private/AFNetworking/AFXMLRequestOperation.h new file mode 120000 index 0000000..9b01587 --- /dev/null +++ b/Pods/Headers/Private/AFNetworking/AFXMLRequestOperation.h @@ -0,0 +1 @@ +../../../AFNetworking/AFNetworking/AFXMLRequestOperation.h \ No newline at end of file diff --git a/Pods/Headers/Private/AFNetworking/UIImageView+AFNetworking.h b/Pods/Headers/Private/AFNetworking/UIImageView+AFNetworking.h new file mode 120000 index 0000000..20b48f1 --- /dev/null +++ b/Pods/Headers/Private/AFNetworking/UIImageView+AFNetworking.h @@ -0,0 +1 @@ +../../../AFNetworking/AFNetworking/UIImageView+AFNetworking.h \ No newline at end of file diff --git a/Pods/Headers/Private/ISO8601DateFormatterValueTransformer/ISO8601DateFormatterValueTransformer.h b/Pods/Headers/Private/ISO8601DateFormatterValueTransformer/ISO8601DateFormatterValueTransformer.h new file mode 120000 index 0000000..932a9db --- /dev/null +++ b/Pods/Headers/Private/ISO8601DateFormatterValueTransformer/ISO8601DateFormatterValueTransformer.h @@ -0,0 +1 @@ +../../../ISO8601DateFormatterValueTransformer/Code/ISO8601DateFormatterValueTransformer.h \ No newline at end of file diff --git a/Pods/Headers/Private/ISO8601DateFormatterValueTransformer/RKISO8601DateFormatter.h b/Pods/Headers/Private/ISO8601DateFormatterValueTransformer/RKISO8601DateFormatter.h new file mode 120000 index 0000000..79788f6 --- /dev/null +++ b/Pods/Headers/Private/ISO8601DateFormatterValueTransformer/RKISO8601DateFormatter.h @@ -0,0 +1 @@ +../../../ISO8601DateFormatterValueTransformer/Code/RKISO8601DateFormatter.h \ No newline at end of file diff --git a/Pods/Headers/Private/RKValueTransformers/RKValueTransformers.h b/Pods/Headers/Private/RKValueTransformers/RKValueTransformers.h new file mode 120000 index 0000000..7768a97 --- /dev/null +++ b/Pods/Headers/Private/RKValueTransformers/RKValueTransformers.h @@ -0,0 +1 @@ +../../../RKValueTransformers/Code/RKValueTransformers.h \ No newline at end of file diff --git a/Pods/Headers/Private/RestKit/CoreData.h b/Pods/Headers/Private/RestKit/CoreData.h new file mode 120000 index 0000000..938f887 --- /dev/null +++ b/Pods/Headers/Private/RestKit/CoreData.h @@ -0,0 +1 @@ +../../../RestKit/Code/CoreData.h \ No newline at end of file diff --git a/Pods/Headers/Private/RestKit/CoreData/NSManagedObject+RKAdditions.h b/Pods/Headers/Private/RestKit/CoreData/NSManagedObject+RKAdditions.h new file mode 120000 index 0000000..bd245ec --- /dev/null +++ b/Pods/Headers/Private/RestKit/CoreData/NSManagedObject+RKAdditions.h @@ -0,0 +1 @@ +../../../../RestKit/Code/CoreData/NSManagedObject+RKAdditions.h \ No newline at end of file diff --git a/Pods/Headers/Private/RestKit/CoreData/NSManagedObjectContext+RKAdditions.h b/Pods/Headers/Private/RestKit/CoreData/NSManagedObjectContext+RKAdditions.h new file mode 120000 index 0000000..5129d8f --- /dev/null +++ b/Pods/Headers/Private/RestKit/CoreData/NSManagedObjectContext+RKAdditions.h @@ -0,0 +1 @@ +../../../../RestKit/Code/CoreData/NSManagedObjectContext+RKAdditions.h \ No newline at end of file diff --git a/Pods/Headers/Private/RestKit/CoreData/RKConnectionDescription.h b/Pods/Headers/Private/RestKit/CoreData/RKConnectionDescription.h new file mode 120000 index 0000000..ac38741 --- /dev/null +++ b/Pods/Headers/Private/RestKit/CoreData/RKConnectionDescription.h @@ -0,0 +1 @@ +../../../../RestKit/Code/CoreData/RKConnectionDescription.h \ No newline at end of file diff --git a/Pods/Headers/Private/RestKit/CoreData/RKCoreData.h b/Pods/Headers/Private/RestKit/CoreData/RKCoreData.h new file mode 120000 index 0000000..91d61b6 --- /dev/null +++ b/Pods/Headers/Private/RestKit/CoreData/RKCoreData.h @@ -0,0 +1 @@ +../../../../RestKit/Code/CoreData/RKCoreData.h \ No newline at end of file diff --git a/Pods/Headers/Private/RestKit/CoreData/RKEntityByAttributeCache.h b/Pods/Headers/Private/RestKit/CoreData/RKEntityByAttributeCache.h new file mode 120000 index 0000000..aabbe42 --- /dev/null +++ b/Pods/Headers/Private/RestKit/CoreData/RKEntityByAttributeCache.h @@ -0,0 +1 @@ +../../../../RestKit/Code/CoreData/RKEntityByAttributeCache.h \ No newline at end of file diff --git a/Pods/Headers/Private/RestKit/CoreData/RKEntityCache.h b/Pods/Headers/Private/RestKit/CoreData/RKEntityCache.h new file mode 120000 index 0000000..5e6d65d --- /dev/null +++ b/Pods/Headers/Private/RestKit/CoreData/RKEntityCache.h @@ -0,0 +1 @@ +../../../../RestKit/Code/CoreData/RKEntityCache.h \ No newline at end of file diff --git a/Pods/Headers/Private/RestKit/CoreData/RKEntityMapping.h b/Pods/Headers/Private/RestKit/CoreData/RKEntityMapping.h new file mode 120000 index 0000000..bf7a764 --- /dev/null +++ b/Pods/Headers/Private/RestKit/CoreData/RKEntityMapping.h @@ -0,0 +1 @@ +../../../../RestKit/Code/CoreData/RKEntityMapping.h \ No newline at end of file diff --git a/Pods/Headers/Private/RestKit/CoreData/RKFetchRequestManagedObjectCache.h b/Pods/Headers/Private/RestKit/CoreData/RKFetchRequestManagedObjectCache.h new file mode 120000 index 0000000..b71783d --- /dev/null +++ b/Pods/Headers/Private/RestKit/CoreData/RKFetchRequestManagedObjectCache.h @@ -0,0 +1 @@ +../../../../RestKit/Code/CoreData/RKFetchRequestManagedObjectCache.h \ No newline at end of file diff --git a/Pods/Headers/Private/RestKit/CoreData/RKInMemoryManagedObjectCache.h b/Pods/Headers/Private/RestKit/CoreData/RKInMemoryManagedObjectCache.h new file mode 120000 index 0000000..e133edd --- /dev/null +++ b/Pods/Headers/Private/RestKit/CoreData/RKInMemoryManagedObjectCache.h @@ -0,0 +1 @@ +../../../../RestKit/Code/CoreData/RKInMemoryManagedObjectCache.h \ No newline at end of file diff --git a/Pods/Headers/Private/RestKit/CoreData/RKManagedObjectCaching.h b/Pods/Headers/Private/RestKit/CoreData/RKManagedObjectCaching.h new file mode 120000 index 0000000..4850ebe --- /dev/null +++ b/Pods/Headers/Private/RestKit/CoreData/RKManagedObjectCaching.h @@ -0,0 +1 @@ +../../../../RestKit/Code/CoreData/RKManagedObjectCaching.h \ No newline at end of file diff --git a/Pods/Headers/Private/RestKit/CoreData/RKManagedObjectImporter.h b/Pods/Headers/Private/RestKit/CoreData/RKManagedObjectImporter.h new file mode 120000 index 0000000..895a95b --- /dev/null +++ b/Pods/Headers/Private/RestKit/CoreData/RKManagedObjectImporter.h @@ -0,0 +1 @@ +../../../../RestKit/Code/CoreData/RKManagedObjectImporter.h \ No newline at end of file diff --git a/Pods/Headers/Private/RestKit/CoreData/RKManagedObjectMappingOperationDataSource.h b/Pods/Headers/Private/RestKit/CoreData/RKManagedObjectMappingOperationDataSource.h new file mode 120000 index 0000000..63c21c8 --- /dev/null +++ b/Pods/Headers/Private/RestKit/CoreData/RKManagedObjectMappingOperationDataSource.h @@ -0,0 +1 @@ +../../../../RestKit/Code/CoreData/RKManagedObjectMappingOperationDataSource.h \ No newline at end of file diff --git a/Pods/Headers/Private/RestKit/CoreData/RKManagedObjectStore.h b/Pods/Headers/Private/RestKit/CoreData/RKManagedObjectStore.h new file mode 120000 index 0000000..c2abf47 --- /dev/null +++ b/Pods/Headers/Private/RestKit/CoreData/RKManagedObjectStore.h @@ -0,0 +1 @@ +../../../../RestKit/Code/CoreData/RKManagedObjectStore.h \ No newline at end of file diff --git a/Pods/Headers/Private/RestKit/CoreData/RKPropertyInspector+CoreData.h b/Pods/Headers/Private/RestKit/CoreData/RKPropertyInspector+CoreData.h new file mode 120000 index 0000000..9c57f2d --- /dev/null +++ b/Pods/Headers/Private/RestKit/CoreData/RKPropertyInspector+CoreData.h @@ -0,0 +1 @@ +../../../../RestKit/Code/CoreData/RKPropertyInspector+CoreData.h \ No newline at end of file diff --git a/Pods/Headers/Private/RestKit/CoreData/RKRelationshipConnectionOperation.h b/Pods/Headers/Private/RestKit/CoreData/RKRelationshipConnectionOperation.h new file mode 120000 index 0000000..80e3ca7 --- /dev/null +++ b/Pods/Headers/Private/RestKit/CoreData/RKRelationshipConnectionOperation.h @@ -0,0 +1 @@ +../../../../RestKit/Code/CoreData/RKRelationshipConnectionOperation.h \ No newline at end of file diff --git a/Pods/Headers/Private/RestKit/Network.h b/Pods/Headers/Private/RestKit/Network.h new file mode 120000 index 0000000..5210a78 --- /dev/null +++ b/Pods/Headers/Private/RestKit/Network.h @@ -0,0 +1 @@ +../../../RestKit/Code/Network.h \ No newline at end of file diff --git a/Pods/Headers/Private/RestKit/Network/RKHTTPRequestOperation.h b/Pods/Headers/Private/RestKit/Network/RKHTTPRequestOperation.h new file mode 120000 index 0000000..2b63c3c --- /dev/null +++ b/Pods/Headers/Private/RestKit/Network/RKHTTPRequestOperation.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Network/RKHTTPRequestOperation.h \ No newline at end of file diff --git a/Pods/Headers/Private/RestKit/Network/RKManagedObjectRequestOperation.h b/Pods/Headers/Private/RestKit/Network/RKManagedObjectRequestOperation.h new file mode 120000 index 0000000..c5f5677 --- /dev/null +++ b/Pods/Headers/Private/RestKit/Network/RKManagedObjectRequestOperation.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Network/RKManagedObjectRequestOperation.h \ No newline at end of file diff --git a/Pods/Headers/Private/RestKit/Network/RKObjectManager.h b/Pods/Headers/Private/RestKit/Network/RKObjectManager.h new file mode 120000 index 0000000..f67267f --- /dev/null +++ b/Pods/Headers/Private/RestKit/Network/RKObjectManager.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Network/RKObjectManager.h \ No newline at end of file diff --git a/Pods/Headers/Private/RestKit/Network/RKObjectParameterization.h b/Pods/Headers/Private/RestKit/Network/RKObjectParameterization.h new file mode 120000 index 0000000..73e232c --- /dev/null +++ b/Pods/Headers/Private/RestKit/Network/RKObjectParameterization.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Network/RKObjectParameterization.h \ No newline at end of file diff --git a/Pods/Headers/Private/RestKit/Network/RKObjectRequestOperation.h b/Pods/Headers/Private/RestKit/Network/RKObjectRequestOperation.h new file mode 120000 index 0000000..e4dbe06 --- /dev/null +++ b/Pods/Headers/Private/RestKit/Network/RKObjectRequestOperation.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Network/RKObjectRequestOperation.h \ No newline at end of file diff --git a/Pods/Headers/Private/RestKit/Network/RKObjectRequestOperationSubclass.h b/Pods/Headers/Private/RestKit/Network/RKObjectRequestOperationSubclass.h new file mode 120000 index 0000000..d0ca904 --- /dev/null +++ b/Pods/Headers/Private/RestKit/Network/RKObjectRequestOperationSubclass.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Network/RKObjectRequestOperationSubclass.h \ No newline at end of file diff --git a/Pods/Headers/Private/RestKit/Network/RKPaginator.h b/Pods/Headers/Private/RestKit/Network/RKPaginator.h new file mode 120000 index 0000000..35b421e --- /dev/null +++ b/Pods/Headers/Private/RestKit/Network/RKPaginator.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Network/RKPaginator.h \ No newline at end of file diff --git a/Pods/Headers/Private/RestKit/Network/RKPathMatcher.h b/Pods/Headers/Private/RestKit/Network/RKPathMatcher.h new file mode 120000 index 0000000..73ab1e6 --- /dev/null +++ b/Pods/Headers/Private/RestKit/Network/RKPathMatcher.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Network/RKPathMatcher.h \ No newline at end of file diff --git a/Pods/Headers/Private/RestKit/Network/RKRequestDescriptor.h b/Pods/Headers/Private/RestKit/Network/RKRequestDescriptor.h new file mode 120000 index 0000000..7f8e8b3 --- /dev/null +++ b/Pods/Headers/Private/RestKit/Network/RKRequestDescriptor.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Network/RKRequestDescriptor.h \ No newline at end of file diff --git a/Pods/Headers/Private/RestKit/Network/RKResponseDescriptor.h b/Pods/Headers/Private/RestKit/Network/RKResponseDescriptor.h new file mode 120000 index 0000000..4981d9a --- /dev/null +++ b/Pods/Headers/Private/RestKit/Network/RKResponseDescriptor.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Network/RKResponseDescriptor.h \ No newline at end of file diff --git a/Pods/Headers/Private/RestKit/Network/RKResponseMapperOperation.h b/Pods/Headers/Private/RestKit/Network/RKResponseMapperOperation.h new file mode 120000 index 0000000..a2e1586 --- /dev/null +++ b/Pods/Headers/Private/RestKit/Network/RKResponseMapperOperation.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Network/RKResponseMapperOperation.h \ No newline at end of file diff --git a/Pods/Headers/Private/RestKit/Network/RKRoute.h b/Pods/Headers/Private/RestKit/Network/RKRoute.h new file mode 120000 index 0000000..39eb2cb --- /dev/null +++ b/Pods/Headers/Private/RestKit/Network/RKRoute.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Network/RKRoute.h \ No newline at end of file diff --git a/Pods/Headers/Private/RestKit/Network/RKRouteSet.h b/Pods/Headers/Private/RestKit/Network/RKRouteSet.h new file mode 120000 index 0000000..a702bdc --- /dev/null +++ b/Pods/Headers/Private/RestKit/Network/RKRouteSet.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Network/RKRouteSet.h \ No newline at end of file diff --git a/Pods/Headers/Private/RestKit/Network/RKRouter.h b/Pods/Headers/Private/RestKit/Network/RKRouter.h new file mode 120000 index 0000000..7187f17 --- /dev/null +++ b/Pods/Headers/Private/RestKit/Network/RKRouter.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Network/RKRouter.h \ No newline at end of file diff --git a/Pods/Headers/Private/RestKit/ObjectMapping.h b/Pods/Headers/Private/RestKit/ObjectMapping.h new file mode 120000 index 0000000..9ca1b53 --- /dev/null +++ b/Pods/Headers/Private/RestKit/ObjectMapping.h @@ -0,0 +1 @@ +../../../RestKit/Code/ObjectMapping.h \ No newline at end of file diff --git a/Pods/Headers/Private/RestKit/ObjectMapping/RKAttributeMapping.h b/Pods/Headers/Private/RestKit/ObjectMapping/RKAttributeMapping.h new file mode 120000 index 0000000..b196d35 --- /dev/null +++ b/Pods/Headers/Private/RestKit/ObjectMapping/RKAttributeMapping.h @@ -0,0 +1 @@ +../../../../RestKit/Code/ObjectMapping/RKAttributeMapping.h \ No newline at end of file diff --git a/Pods/Headers/Private/RestKit/ObjectMapping/RKDynamicMapping.h b/Pods/Headers/Private/RestKit/ObjectMapping/RKDynamicMapping.h new file mode 120000 index 0000000..67a1caf --- /dev/null +++ b/Pods/Headers/Private/RestKit/ObjectMapping/RKDynamicMapping.h @@ -0,0 +1 @@ +../../../../RestKit/Code/ObjectMapping/RKDynamicMapping.h \ No newline at end of file diff --git a/Pods/Headers/Private/RestKit/ObjectMapping/RKErrorMessage.h b/Pods/Headers/Private/RestKit/ObjectMapping/RKErrorMessage.h new file mode 120000 index 0000000..6d6996d --- /dev/null +++ b/Pods/Headers/Private/RestKit/ObjectMapping/RKErrorMessage.h @@ -0,0 +1 @@ +../../../../RestKit/Code/ObjectMapping/RKErrorMessage.h \ No newline at end of file diff --git a/Pods/Headers/Private/RestKit/ObjectMapping/RKHTTPUtilities.h b/Pods/Headers/Private/RestKit/ObjectMapping/RKHTTPUtilities.h new file mode 120000 index 0000000..318d5c2 --- /dev/null +++ b/Pods/Headers/Private/RestKit/ObjectMapping/RKHTTPUtilities.h @@ -0,0 +1 @@ +../../../../RestKit/Code/ObjectMapping/RKHTTPUtilities.h \ No newline at end of file diff --git a/Pods/Headers/Private/RestKit/ObjectMapping/RKMapperOperation.h b/Pods/Headers/Private/RestKit/ObjectMapping/RKMapperOperation.h new file mode 120000 index 0000000..59e87e2 --- /dev/null +++ b/Pods/Headers/Private/RestKit/ObjectMapping/RKMapperOperation.h @@ -0,0 +1 @@ +../../../../RestKit/Code/ObjectMapping/RKMapperOperation.h \ No newline at end of file diff --git a/Pods/Headers/Private/RestKit/ObjectMapping/RKMapperOperation_Private.h b/Pods/Headers/Private/RestKit/ObjectMapping/RKMapperOperation_Private.h new file mode 120000 index 0000000..bd32976 --- /dev/null +++ b/Pods/Headers/Private/RestKit/ObjectMapping/RKMapperOperation_Private.h @@ -0,0 +1 @@ +../../../../RestKit/Code/ObjectMapping/RKMapperOperation_Private.h \ No newline at end of file diff --git a/Pods/Headers/Private/RestKit/ObjectMapping/RKMapping.h b/Pods/Headers/Private/RestKit/ObjectMapping/RKMapping.h new file mode 120000 index 0000000..6aaec37 --- /dev/null +++ b/Pods/Headers/Private/RestKit/ObjectMapping/RKMapping.h @@ -0,0 +1 @@ +../../../../RestKit/Code/ObjectMapping/RKMapping.h \ No newline at end of file diff --git a/Pods/Headers/Private/RestKit/ObjectMapping/RKMappingErrors.h b/Pods/Headers/Private/RestKit/ObjectMapping/RKMappingErrors.h new file mode 120000 index 0000000..68e3925 --- /dev/null +++ b/Pods/Headers/Private/RestKit/ObjectMapping/RKMappingErrors.h @@ -0,0 +1 @@ +../../../../RestKit/Code/ObjectMapping/RKMappingErrors.h \ No newline at end of file diff --git a/Pods/Headers/Private/RestKit/ObjectMapping/RKMappingOperation.h b/Pods/Headers/Private/RestKit/ObjectMapping/RKMappingOperation.h new file mode 120000 index 0000000..6b4d1bf --- /dev/null +++ b/Pods/Headers/Private/RestKit/ObjectMapping/RKMappingOperation.h @@ -0,0 +1 @@ +../../../../RestKit/Code/ObjectMapping/RKMappingOperation.h \ No newline at end of file diff --git a/Pods/Headers/Private/RestKit/ObjectMapping/RKMappingOperationDataSource.h b/Pods/Headers/Private/RestKit/ObjectMapping/RKMappingOperationDataSource.h new file mode 120000 index 0000000..d463834 --- /dev/null +++ b/Pods/Headers/Private/RestKit/ObjectMapping/RKMappingOperationDataSource.h @@ -0,0 +1 @@ +../../../../RestKit/Code/ObjectMapping/RKMappingOperationDataSource.h \ No newline at end of file diff --git a/Pods/Headers/Private/RestKit/ObjectMapping/RKMappingResult.h b/Pods/Headers/Private/RestKit/ObjectMapping/RKMappingResult.h new file mode 120000 index 0000000..03618d2 --- /dev/null +++ b/Pods/Headers/Private/RestKit/ObjectMapping/RKMappingResult.h @@ -0,0 +1 @@ +../../../../RestKit/Code/ObjectMapping/RKMappingResult.h \ No newline at end of file diff --git a/Pods/Headers/Private/RestKit/ObjectMapping/RKObjectMapping.h b/Pods/Headers/Private/RestKit/ObjectMapping/RKObjectMapping.h new file mode 120000 index 0000000..d38ebca --- /dev/null +++ b/Pods/Headers/Private/RestKit/ObjectMapping/RKObjectMapping.h @@ -0,0 +1 @@ +../../../../RestKit/Code/ObjectMapping/RKObjectMapping.h \ No newline at end of file diff --git a/Pods/Headers/Private/RestKit/ObjectMapping/RKObjectMappingMatcher.h b/Pods/Headers/Private/RestKit/ObjectMapping/RKObjectMappingMatcher.h new file mode 120000 index 0000000..2664bd7 --- /dev/null +++ b/Pods/Headers/Private/RestKit/ObjectMapping/RKObjectMappingMatcher.h @@ -0,0 +1 @@ +../../../../RestKit/Code/ObjectMapping/RKObjectMappingMatcher.h \ No newline at end of file diff --git a/Pods/Headers/Private/RestKit/ObjectMapping/RKObjectMappingOperationDataSource.h b/Pods/Headers/Private/RestKit/ObjectMapping/RKObjectMappingOperationDataSource.h new file mode 120000 index 0000000..cdac049 --- /dev/null +++ b/Pods/Headers/Private/RestKit/ObjectMapping/RKObjectMappingOperationDataSource.h @@ -0,0 +1 @@ +../../../../RestKit/Code/ObjectMapping/RKObjectMappingOperationDataSource.h \ No newline at end of file diff --git a/Pods/Headers/Private/RestKit/ObjectMapping/RKObjectUtilities.h b/Pods/Headers/Private/RestKit/ObjectMapping/RKObjectUtilities.h new file mode 120000 index 0000000..1ee01f3 --- /dev/null +++ b/Pods/Headers/Private/RestKit/ObjectMapping/RKObjectUtilities.h @@ -0,0 +1 @@ +../../../../RestKit/Code/ObjectMapping/RKObjectUtilities.h \ No newline at end of file diff --git a/Pods/Headers/Private/RestKit/ObjectMapping/RKPropertyInspector.h b/Pods/Headers/Private/RestKit/ObjectMapping/RKPropertyInspector.h new file mode 120000 index 0000000..a3e2a9d --- /dev/null +++ b/Pods/Headers/Private/RestKit/ObjectMapping/RKPropertyInspector.h @@ -0,0 +1 @@ +../../../../RestKit/Code/ObjectMapping/RKPropertyInspector.h \ No newline at end of file diff --git a/Pods/Headers/Private/RestKit/ObjectMapping/RKPropertyMapping.h b/Pods/Headers/Private/RestKit/ObjectMapping/RKPropertyMapping.h new file mode 120000 index 0000000..db4bc5c --- /dev/null +++ b/Pods/Headers/Private/RestKit/ObjectMapping/RKPropertyMapping.h @@ -0,0 +1 @@ +../../../../RestKit/Code/ObjectMapping/RKPropertyMapping.h \ No newline at end of file diff --git a/Pods/Headers/Private/RestKit/ObjectMapping/RKRelationshipMapping.h b/Pods/Headers/Private/RestKit/ObjectMapping/RKRelationshipMapping.h new file mode 120000 index 0000000..32b9847 --- /dev/null +++ b/Pods/Headers/Private/RestKit/ObjectMapping/RKRelationshipMapping.h @@ -0,0 +1 @@ +../../../../RestKit/Code/ObjectMapping/RKRelationshipMapping.h \ No newline at end of file diff --git a/Pods/Headers/Private/RestKit/RestKit.h b/Pods/Headers/Private/RestKit/RestKit.h new file mode 120000 index 0000000..49e183c --- /dev/null +++ b/Pods/Headers/Private/RestKit/RestKit.h @@ -0,0 +1 @@ +../../../RestKit/Code/RestKit.h \ No newline at end of file diff --git a/Pods/Headers/Private/RestKit/Support.h b/Pods/Headers/Private/RestKit/Support.h new file mode 120000 index 0000000..06fa6db --- /dev/null +++ b/Pods/Headers/Private/RestKit/Support.h @@ -0,0 +1 @@ +../../../RestKit/Code/Support.h \ No newline at end of file diff --git a/Pods/Headers/Private/RestKit/Support/RKDictionaryUtilities.h b/Pods/Headers/Private/RestKit/Support/RKDictionaryUtilities.h new file mode 120000 index 0000000..f4e0175 --- /dev/null +++ b/Pods/Headers/Private/RestKit/Support/RKDictionaryUtilities.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Support/RKDictionaryUtilities.h \ No newline at end of file diff --git a/Pods/Headers/Private/RestKit/Support/RKDotNetDateFormatter.h b/Pods/Headers/Private/RestKit/Support/RKDotNetDateFormatter.h new file mode 120000 index 0000000..44ee028 --- /dev/null +++ b/Pods/Headers/Private/RestKit/Support/RKDotNetDateFormatter.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Support/RKDotNetDateFormatter.h \ No newline at end of file diff --git a/Pods/Headers/Private/RestKit/Support/RKErrors.h b/Pods/Headers/Private/RestKit/Support/RKErrors.h new file mode 120000 index 0000000..7319216 --- /dev/null +++ b/Pods/Headers/Private/RestKit/Support/RKErrors.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Support/RKErrors.h \ No newline at end of file diff --git a/Pods/Headers/Private/RestKit/Support/RKLog.h b/Pods/Headers/Private/RestKit/Support/RKLog.h new file mode 120000 index 0000000..6a428cb --- /dev/null +++ b/Pods/Headers/Private/RestKit/Support/RKLog.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Support/RKLog.h \ No newline at end of file diff --git a/Pods/Headers/Private/RestKit/Support/RKLumberjackLogger.h b/Pods/Headers/Private/RestKit/Support/RKLumberjackLogger.h new file mode 120000 index 0000000..b8d134c --- /dev/null +++ b/Pods/Headers/Private/RestKit/Support/RKLumberjackLogger.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Support/RKLumberjackLogger.h \ No newline at end of file diff --git a/Pods/Headers/Private/RestKit/Support/RKMIMETypeSerialization.h b/Pods/Headers/Private/RestKit/Support/RKMIMETypeSerialization.h new file mode 120000 index 0000000..b77b8b3 --- /dev/null +++ b/Pods/Headers/Private/RestKit/Support/RKMIMETypeSerialization.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Support/RKMIMETypeSerialization.h \ No newline at end of file diff --git a/Pods/Headers/Private/RestKit/Support/RKMIMETypes.h b/Pods/Headers/Private/RestKit/Support/RKMIMETypes.h new file mode 120000 index 0000000..71b36c8 --- /dev/null +++ b/Pods/Headers/Private/RestKit/Support/RKMIMETypes.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Support/RKMIMETypes.h \ No newline at end of file diff --git a/Pods/Headers/Private/RestKit/Support/RKMacros.h b/Pods/Headers/Private/RestKit/Support/RKMacros.h new file mode 120000 index 0000000..f1d842d --- /dev/null +++ b/Pods/Headers/Private/RestKit/Support/RKMacros.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Support/RKMacros.h \ No newline at end of file diff --git a/Pods/Headers/Private/RestKit/Support/RKNSJSONSerialization.h b/Pods/Headers/Private/RestKit/Support/RKNSJSONSerialization.h new file mode 120000 index 0000000..537580d --- /dev/null +++ b/Pods/Headers/Private/RestKit/Support/RKNSJSONSerialization.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Support/RKNSJSONSerialization.h \ No newline at end of file diff --git a/Pods/Headers/Private/RestKit/Support/RKOperationStateMachine.h b/Pods/Headers/Private/RestKit/Support/RKOperationStateMachine.h new file mode 120000 index 0000000..1391329 --- /dev/null +++ b/Pods/Headers/Private/RestKit/Support/RKOperationStateMachine.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Support/RKOperationStateMachine.h \ No newline at end of file diff --git a/Pods/Headers/Private/RestKit/Support/RKPathUtilities.h b/Pods/Headers/Private/RestKit/Support/RKPathUtilities.h new file mode 120000 index 0000000..2ef3a20 --- /dev/null +++ b/Pods/Headers/Private/RestKit/Support/RKPathUtilities.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Support/RKPathUtilities.h \ No newline at end of file diff --git a/Pods/Headers/Private/RestKit/Support/RKSerialization.h b/Pods/Headers/Private/RestKit/Support/RKSerialization.h new file mode 120000 index 0000000..b66ce92 --- /dev/null +++ b/Pods/Headers/Private/RestKit/Support/RKSerialization.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Support/RKSerialization.h \ No newline at end of file diff --git a/Pods/Headers/Private/RestKit/Support/RKStringTokenizer.h b/Pods/Headers/Private/RestKit/Support/RKStringTokenizer.h new file mode 120000 index 0000000..6535c08 --- /dev/null +++ b/Pods/Headers/Private/RestKit/Support/RKStringTokenizer.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Support/RKStringTokenizer.h \ No newline at end of file diff --git a/Pods/Headers/Private/RestKit/Support/RKURLEncodedSerialization.h b/Pods/Headers/Private/RestKit/Support/RKURLEncodedSerialization.h new file mode 120000 index 0000000..ea62327 --- /dev/null +++ b/Pods/Headers/Private/RestKit/Support/RKURLEncodedSerialization.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Support/RKURLEncodedSerialization.h \ No newline at end of file diff --git a/Pods/Headers/Private/RestKit/Support/lcl_config_components_RK.h b/Pods/Headers/Private/RestKit/Support/lcl_config_components_RK.h new file mode 120000 index 0000000..7902c5b --- /dev/null +++ b/Pods/Headers/Private/RestKit/Support/lcl_config_components_RK.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Support/lcl_config_components_RK.h \ No newline at end of file diff --git a/Pods/Headers/Private/RestKit/Support/lcl_config_extensions_RK.h b/Pods/Headers/Private/RestKit/Support/lcl_config_extensions_RK.h new file mode 120000 index 0000000..eff8ca5 --- /dev/null +++ b/Pods/Headers/Private/RestKit/Support/lcl_config_extensions_RK.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Support/lcl_config_extensions_RK.h \ No newline at end of file diff --git a/Pods/Headers/Private/RestKit/Support/lcl_config_logger_RK.h b/Pods/Headers/Private/RestKit/Support/lcl_config_logger_RK.h new file mode 120000 index 0000000..39088b8 --- /dev/null +++ b/Pods/Headers/Private/RestKit/Support/lcl_config_logger_RK.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Support/lcl_config_logger_RK.h \ No newline at end of file diff --git a/Pods/Headers/Private/SOCKit/SOCKit.h b/Pods/Headers/Private/SOCKit/SOCKit.h new file mode 120000 index 0000000..72c5afc --- /dev/null +++ b/Pods/Headers/Private/SOCKit/SOCKit.h @@ -0,0 +1 @@ +../../../SOCKit/SOCKit.h \ No newline at end of file diff --git a/Pods/Headers/Private/TransitionKit/TKEvent.h b/Pods/Headers/Private/TransitionKit/TKEvent.h new file mode 120000 index 0000000..e0febb8 --- /dev/null +++ b/Pods/Headers/Private/TransitionKit/TKEvent.h @@ -0,0 +1 @@ +../../../TransitionKit/Code/TKEvent.h \ No newline at end of file diff --git a/Pods/Headers/Private/TransitionKit/TKState.h b/Pods/Headers/Private/TransitionKit/TKState.h new file mode 120000 index 0000000..6dbd8d3 --- /dev/null +++ b/Pods/Headers/Private/TransitionKit/TKState.h @@ -0,0 +1 @@ +../../../TransitionKit/Code/TKState.h \ No newline at end of file diff --git a/Pods/Headers/Private/TransitionKit/TKStateMachine.h b/Pods/Headers/Private/TransitionKit/TKStateMachine.h new file mode 120000 index 0000000..cfbbd7f --- /dev/null +++ b/Pods/Headers/Private/TransitionKit/TKStateMachine.h @@ -0,0 +1 @@ +../../../TransitionKit/Code/TKStateMachine.h \ No newline at end of file diff --git a/Pods/Headers/Private/TransitionKit/TKTransition.h b/Pods/Headers/Private/TransitionKit/TKTransition.h new file mode 120000 index 0000000..d83dc2c --- /dev/null +++ b/Pods/Headers/Private/TransitionKit/TKTransition.h @@ -0,0 +1 @@ +../../../TransitionKit/Code/TKTransition.h \ No newline at end of file diff --git a/Pods/Headers/Private/TransitionKit/TransitionKit.h b/Pods/Headers/Private/TransitionKit/TransitionKit.h new file mode 120000 index 0000000..d5b6768 --- /dev/null +++ b/Pods/Headers/Private/TransitionKit/TransitionKit.h @@ -0,0 +1 @@ +../../../TransitionKit/Code/TransitionKit.h \ No newline at end of file diff --git a/Pods/Headers/Private/Vendor/LibComponentLogging/Core/lcl_RK.h b/Pods/Headers/Private/Vendor/LibComponentLogging/Core/lcl_RK.h new file mode 120000 index 0000000..d94e2d3 --- /dev/null +++ b/Pods/Headers/Private/Vendor/LibComponentLogging/Core/lcl_RK.h @@ -0,0 +1 @@ +../../../../../RestKit/Vendor/LibComponentLogging/Core/lcl_RK.h \ No newline at end of file diff --git a/Pods/Headers/Public/AFNetworking/AFHTTPClient.h b/Pods/Headers/Public/AFNetworking/AFHTTPClient.h new file mode 120000 index 0000000..aee081b --- /dev/null +++ b/Pods/Headers/Public/AFNetworking/AFHTTPClient.h @@ -0,0 +1 @@ +../../../AFNetworking/AFNetworking/AFHTTPClient.h \ No newline at end of file diff --git a/Pods/Headers/Public/AFNetworking/AFHTTPRequestOperation.h b/Pods/Headers/Public/AFNetworking/AFHTTPRequestOperation.h new file mode 120000 index 0000000..ac762c8 --- /dev/null +++ b/Pods/Headers/Public/AFNetworking/AFHTTPRequestOperation.h @@ -0,0 +1 @@ +../../../AFNetworking/AFNetworking/AFHTTPRequestOperation.h \ No newline at end of file diff --git a/Pods/Headers/Public/AFNetworking/AFImageRequestOperation.h b/Pods/Headers/Public/AFNetworking/AFImageRequestOperation.h new file mode 120000 index 0000000..c1fccfd --- /dev/null +++ b/Pods/Headers/Public/AFNetworking/AFImageRequestOperation.h @@ -0,0 +1 @@ +../../../AFNetworking/AFNetworking/AFImageRequestOperation.h \ No newline at end of file diff --git a/Pods/Headers/Public/AFNetworking/AFJSONRequestOperation.h b/Pods/Headers/Public/AFNetworking/AFJSONRequestOperation.h new file mode 120000 index 0000000..9f2188e --- /dev/null +++ b/Pods/Headers/Public/AFNetworking/AFJSONRequestOperation.h @@ -0,0 +1 @@ +../../../AFNetworking/AFNetworking/AFJSONRequestOperation.h \ No newline at end of file diff --git a/Pods/Headers/Public/AFNetworking/AFNetworkActivityIndicatorManager.h b/Pods/Headers/Public/AFNetworking/AFNetworkActivityIndicatorManager.h new file mode 120000 index 0000000..f454e54 --- /dev/null +++ b/Pods/Headers/Public/AFNetworking/AFNetworkActivityIndicatorManager.h @@ -0,0 +1 @@ +../../../AFNetworking/AFNetworking/AFNetworkActivityIndicatorManager.h \ No newline at end of file diff --git a/Pods/Headers/Public/AFNetworking/AFNetworking.h b/Pods/Headers/Public/AFNetworking/AFNetworking.h new file mode 120000 index 0000000..a5a38da --- /dev/null +++ b/Pods/Headers/Public/AFNetworking/AFNetworking.h @@ -0,0 +1 @@ +../../../AFNetworking/AFNetworking/AFNetworking.h \ No newline at end of file diff --git a/Pods/Headers/Public/AFNetworking/AFPropertyListRequestOperation.h b/Pods/Headers/Public/AFNetworking/AFPropertyListRequestOperation.h new file mode 120000 index 0000000..4b04bd2 --- /dev/null +++ b/Pods/Headers/Public/AFNetworking/AFPropertyListRequestOperation.h @@ -0,0 +1 @@ +../../../AFNetworking/AFNetworking/AFPropertyListRequestOperation.h \ No newline at end of file diff --git a/Pods/Headers/Public/AFNetworking/AFURLConnectionOperation.h b/Pods/Headers/Public/AFNetworking/AFURLConnectionOperation.h new file mode 120000 index 0000000..d9b35fb --- /dev/null +++ b/Pods/Headers/Public/AFNetworking/AFURLConnectionOperation.h @@ -0,0 +1 @@ +../../../AFNetworking/AFNetworking/AFURLConnectionOperation.h \ No newline at end of file diff --git a/Pods/Headers/Public/AFNetworking/AFXMLRequestOperation.h b/Pods/Headers/Public/AFNetworking/AFXMLRequestOperation.h new file mode 120000 index 0000000..9b01587 --- /dev/null +++ b/Pods/Headers/Public/AFNetworking/AFXMLRequestOperation.h @@ -0,0 +1 @@ +../../../AFNetworking/AFNetworking/AFXMLRequestOperation.h \ No newline at end of file diff --git a/Pods/Headers/Public/AFNetworking/UIImageView+AFNetworking.h b/Pods/Headers/Public/AFNetworking/UIImageView+AFNetworking.h new file mode 120000 index 0000000..20b48f1 --- /dev/null +++ b/Pods/Headers/Public/AFNetworking/UIImageView+AFNetworking.h @@ -0,0 +1 @@ +../../../AFNetworking/AFNetworking/UIImageView+AFNetworking.h \ No newline at end of file diff --git a/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSAddress.h b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSAddress.h new file mode 120000 index 0000000..e90bc36 --- /dev/null +++ b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSAddress.h @@ -0,0 +1 @@ +../../../../GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSAddress.h \ No newline at end of file diff --git a/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSAutocompleteFilter.h b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSAutocompleteFilter.h new file mode 120000 index 0000000..481b137 --- /dev/null +++ b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSAutocompleteFilter.h @@ -0,0 +1 @@ +../../../../GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSAutocompleteFilter.h \ No newline at end of file diff --git a/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSAutocompleteMatchFragment.h b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSAutocompleteMatchFragment.h new file mode 120000 index 0000000..35dd8ce --- /dev/null +++ b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSAutocompleteMatchFragment.h @@ -0,0 +1 @@ +../../../../GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSAutocompleteMatchFragment.h \ No newline at end of file diff --git a/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSAutocompletePrediction.h b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSAutocompletePrediction.h new file mode 120000 index 0000000..1d0b893 --- /dev/null +++ b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSAutocompletePrediction.h @@ -0,0 +1 @@ +../../../../GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSAutocompletePrediction.h \ No newline at end of file diff --git a/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSCALayer.h b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSCALayer.h new file mode 120000 index 0000000..28ee5f1 --- /dev/null +++ b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSCALayer.h @@ -0,0 +1 @@ +../../../../GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSCALayer.h \ No newline at end of file diff --git a/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSCameraPosition.h b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSCameraPosition.h new file mode 120000 index 0000000..378aded --- /dev/null +++ b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSCameraPosition.h @@ -0,0 +1 @@ +../../../../GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSCameraPosition.h \ No newline at end of file diff --git a/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSCameraUpdate.h b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSCameraUpdate.h new file mode 120000 index 0000000..1750643 --- /dev/null +++ b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSCameraUpdate.h @@ -0,0 +1 @@ +../../../../GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSCameraUpdate.h \ No newline at end of file diff --git a/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSCircle.h b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSCircle.h new file mode 120000 index 0000000..97cf3b4 --- /dev/null +++ b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSCircle.h @@ -0,0 +1 @@ +../../../../GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSCircle.h \ No newline at end of file diff --git a/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSCoordinateBounds.h b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSCoordinateBounds.h new file mode 120000 index 0000000..b8f035b --- /dev/null +++ b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSCoordinateBounds.h @@ -0,0 +1 @@ +../../../../GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSCoordinateBounds.h \ No newline at end of file diff --git a/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSGeocoder.h b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSGeocoder.h new file mode 120000 index 0000000..3ce1121 --- /dev/null +++ b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSGeocoder.h @@ -0,0 +1 @@ +../../../../GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSGeocoder.h \ No newline at end of file diff --git a/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSGeometryUtils.h b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSGeometryUtils.h new file mode 120000 index 0000000..5e0ca0a --- /dev/null +++ b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSGeometryUtils.h @@ -0,0 +1 @@ +../../../../GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSGeometryUtils.h \ No newline at end of file diff --git a/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSGroundOverlay.h b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSGroundOverlay.h new file mode 120000 index 0000000..dc73548 --- /dev/null +++ b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSGroundOverlay.h @@ -0,0 +1 @@ +../../../../GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSGroundOverlay.h \ No newline at end of file diff --git a/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSIndoorBuilding.h b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSIndoorBuilding.h new file mode 120000 index 0000000..a0d4dae --- /dev/null +++ b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSIndoorBuilding.h @@ -0,0 +1 @@ +../../../../GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSIndoorBuilding.h \ No newline at end of file diff --git a/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSIndoorDisplay.h b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSIndoorDisplay.h new file mode 120000 index 0000000..59d87f8 --- /dev/null +++ b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSIndoorDisplay.h @@ -0,0 +1 @@ +../../../../GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSIndoorDisplay.h \ No newline at end of file diff --git a/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSIndoorLevel.h b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSIndoorLevel.h new file mode 120000 index 0000000..e662766 --- /dev/null +++ b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSIndoorLevel.h @@ -0,0 +1 @@ +../../../../GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSIndoorLevel.h \ No newline at end of file diff --git a/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSMapLayer.h b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSMapLayer.h new file mode 120000 index 0000000..b794812 --- /dev/null +++ b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSMapLayer.h @@ -0,0 +1 @@ +../../../../GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSMapLayer.h \ No newline at end of file diff --git a/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSMapView+Animation.h b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSMapView+Animation.h new file mode 120000 index 0000000..e514ed7 --- /dev/null +++ b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSMapView+Animation.h @@ -0,0 +1 @@ +../../../../GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSMapView+Animation.h \ No newline at end of file diff --git a/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSMapView.h b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSMapView.h new file mode 120000 index 0000000..ede2388 --- /dev/null +++ b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSMapView.h @@ -0,0 +1 @@ +../../../../GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSMapView.h \ No newline at end of file diff --git a/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSMarker.h b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSMarker.h new file mode 120000 index 0000000..f756122 --- /dev/null +++ b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSMarker.h @@ -0,0 +1 @@ +../../../../GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSMarker.h \ No newline at end of file diff --git a/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSMarkerLayer.h b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSMarkerLayer.h new file mode 120000 index 0000000..9f2229c --- /dev/null +++ b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSMarkerLayer.h @@ -0,0 +1 @@ +../../../../GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSMarkerLayer.h \ No newline at end of file diff --git a/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSMutablePath.h b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSMutablePath.h new file mode 120000 index 0000000..0019964 --- /dev/null +++ b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSMutablePath.h @@ -0,0 +1 @@ +../../../../GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSMutablePath.h \ No newline at end of file diff --git a/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSOrientation.h b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSOrientation.h new file mode 120000 index 0000000..56c98c6 --- /dev/null +++ b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSOrientation.h @@ -0,0 +1 @@ +../../../../GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSOrientation.h \ No newline at end of file diff --git a/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSOverlay.h b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSOverlay.h new file mode 120000 index 0000000..446d69f --- /dev/null +++ b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSOverlay.h @@ -0,0 +1 @@ +../../../../GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSOverlay.h \ No newline at end of file diff --git a/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSPanorama.h b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSPanorama.h new file mode 120000 index 0000000..5ed18c8 --- /dev/null +++ b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSPanorama.h @@ -0,0 +1 @@ +../../../../GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSPanorama.h \ No newline at end of file diff --git a/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSPanoramaCamera.h b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSPanoramaCamera.h new file mode 120000 index 0000000..84670fe --- /dev/null +++ b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSPanoramaCamera.h @@ -0,0 +1 @@ +../../../../GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSPanoramaCamera.h \ No newline at end of file diff --git a/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSPanoramaCameraUpdate.h b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSPanoramaCameraUpdate.h new file mode 120000 index 0000000..57a601c --- /dev/null +++ b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSPanoramaCameraUpdate.h @@ -0,0 +1 @@ +../../../../GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSPanoramaCameraUpdate.h \ No newline at end of file diff --git a/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSPanoramaLayer.h b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSPanoramaLayer.h new file mode 120000 index 0000000..822f8b1 --- /dev/null +++ b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSPanoramaLayer.h @@ -0,0 +1 @@ +../../../../GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSPanoramaLayer.h \ No newline at end of file diff --git a/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSPanoramaLink.h b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSPanoramaLink.h new file mode 120000 index 0000000..bd626ae --- /dev/null +++ b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSPanoramaLink.h @@ -0,0 +1 @@ +../../../../GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSPanoramaLink.h \ No newline at end of file diff --git a/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSPanoramaService.h b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSPanoramaService.h new file mode 120000 index 0000000..1b54576 --- /dev/null +++ b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSPanoramaService.h @@ -0,0 +1 @@ +../../../../GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSPanoramaService.h \ No newline at end of file diff --git a/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSPanoramaView.h b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSPanoramaView.h new file mode 120000 index 0000000..2dd1b1d --- /dev/null +++ b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSPanoramaView.h @@ -0,0 +1 @@ +../../../../GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSPanoramaView.h \ No newline at end of file diff --git a/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSPath.h b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSPath.h new file mode 120000 index 0000000..0c77038 --- /dev/null +++ b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSPath.h @@ -0,0 +1 @@ +../../../../GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSPath.h \ No newline at end of file diff --git a/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSPlace.h b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSPlace.h new file mode 120000 index 0000000..9afb1ed --- /dev/null +++ b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSPlace.h @@ -0,0 +1 @@ +../../../../GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSPlace.h \ No newline at end of file diff --git a/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSPlaceLikelihood.h b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSPlaceLikelihood.h new file mode 120000 index 0000000..8de608a --- /dev/null +++ b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSPlaceLikelihood.h @@ -0,0 +1 @@ +../../../../GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSPlaceLikelihood.h \ No newline at end of file diff --git a/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSPlaceLikelihoodList.h b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSPlaceLikelihoodList.h new file mode 120000 index 0000000..a471b77 --- /dev/null +++ b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSPlaceLikelihoodList.h @@ -0,0 +1 @@ +../../../../GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSPlaceLikelihoodList.h \ No newline at end of file diff --git a/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSPlacePicker.h b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSPlacePicker.h new file mode 120000 index 0000000..c521b88 --- /dev/null +++ b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSPlacePicker.h @@ -0,0 +1 @@ +../../../../GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSPlacePicker.h \ No newline at end of file diff --git a/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSPlacePickerConfig.h b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSPlacePickerConfig.h new file mode 120000 index 0000000..f3df3de --- /dev/null +++ b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSPlacePickerConfig.h @@ -0,0 +1 @@ +../../../../GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSPlacePickerConfig.h \ No newline at end of file diff --git a/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSPlaceTypes.h b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSPlaceTypes.h new file mode 120000 index 0000000..437a1a7 --- /dev/null +++ b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSPlaceTypes.h @@ -0,0 +1 @@ +../../../../GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSPlaceTypes.h \ No newline at end of file diff --git a/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSPlacesClient.h b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSPlacesClient.h new file mode 120000 index 0000000..360582a --- /dev/null +++ b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSPlacesClient.h @@ -0,0 +1 @@ +../../../../GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSPlacesClient.h \ No newline at end of file diff --git a/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSPlacesMacros.h b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSPlacesMacros.h new file mode 120000 index 0000000..05d05fe --- /dev/null +++ b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSPlacesMacros.h @@ -0,0 +1 @@ +../../../../GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSPlacesMacros.h \ No newline at end of file diff --git a/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSPolygon.h b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSPolygon.h new file mode 120000 index 0000000..2c636db --- /dev/null +++ b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSPolygon.h @@ -0,0 +1 @@ +../../../../GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSPolygon.h \ No newline at end of file diff --git a/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSPolyline.h b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSPolyline.h new file mode 120000 index 0000000..f8a3104 --- /dev/null +++ b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSPolyline.h @@ -0,0 +1 @@ +../../../../GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSPolyline.h \ No newline at end of file diff --git a/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSProjection.h b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSProjection.h new file mode 120000 index 0000000..3f51982 --- /dev/null +++ b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSProjection.h @@ -0,0 +1 @@ +../../../../GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSProjection.h \ No newline at end of file diff --git a/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSServices.h b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSServices.h new file mode 120000 index 0000000..6fe6119 --- /dev/null +++ b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSServices.h @@ -0,0 +1 @@ +../../../../GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSServices.h \ No newline at end of file diff --git a/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSSyncTileLayer.h b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSSyncTileLayer.h new file mode 120000 index 0000000..c00d001 --- /dev/null +++ b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSSyncTileLayer.h @@ -0,0 +1 @@ +../../../../GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSSyncTileLayer.h \ No newline at end of file diff --git a/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSTileLayer.h b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSTileLayer.h new file mode 120000 index 0000000..4713811 --- /dev/null +++ b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSTileLayer.h @@ -0,0 +1 @@ +../../../../GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSTileLayer.h \ No newline at end of file diff --git a/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSUISettings.h b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSUISettings.h new file mode 120000 index 0000000..8c881d6 --- /dev/null +++ b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSUISettings.h @@ -0,0 +1 @@ +../../../../GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSUISettings.h \ No newline at end of file diff --git a/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSURLTileLayer.h b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSURLTileLayer.h new file mode 120000 index 0000000..52a895a --- /dev/null +++ b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSURLTileLayer.h @@ -0,0 +1 @@ +../../../../GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSURLTileLayer.h \ No newline at end of file diff --git a/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSUserAddedPlace.h b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSUserAddedPlace.h new file mode 120000 index 0000000..f9b53c7 --- /dev/null +++ b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GMSUserAddedPlace.h @@ -0,0 +1 @@ +../../../../GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GMSUserAddedPlace.h \ No newline at end of file diff --git a/Pods/Headers/Public/GoogleMaps/GoogleMaps/GoogleMaps.h b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GoogleMaps.h new file mode 120000 index 0000000..904fee4 --- /dev/null +++ b/Pods/Headers/Public/GoogleMaps/GoogleMaps/GoogleMaps.h @@ -0,0 +1 @@ +../../../../GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Headers/GoogleMaps.h \ No newline at end of file diff --git a/Pods/Headers/Public/ISO8601DateFormatterValueTransformer/ISO8601DateFormatterValueTransformer.h b/Pods/Headers/Public/ISO8601DateFormatterValueTransformer/ISO8601DateFormatterValueTransformer.h new file mode 120000 index 0000000..932a9db --- /dev/null +++ b/Pods/Headers/Public/ISO8601DateFormatterValueTransformer/ISO8601DateFormatterValueTransformer.h @@ -0,0 +1 @@ +../../../ISO8601DateFormatterValueTransformer/Code/ISO8601DateFormatterValueTransformer.h \ No newline at end of file diff --git a/Pods/Headers/Public/ISO8601DateFormatterValueTransformer/RKISO8601DateFormatter.h b/Pods/Headers/Public/ISO8601DateFormatterValueTransformer/RKISO8601DateFormatter.h new file mode 120000 index 0000000..79788f6 --- /dev/null +++ b/Pods/Headers/Public/ISO8601DateFormatterValueTransformer/RKISO8601DateFormatter.h @@ -0,0 +1 @@ +../../../ISO8601DateFormatterValueTransformer/Code/RKISO8601DateFormatter.h \ No newline at end of file diff --git a/Pods/Headers/Public/RKValueTransformers/RKValueTransformers.h b/Pods/Headers/Public/RKValueTransformers/RKValueTransformers.h new file mode 120000 index 0000000..7768a97 --- /dev/null +++ b/Pods/Headers/Public/RKValueTransformers/RKValueTransformers.h @@ -0,0 +1 @@ +../../../RKValueTransformers/Code/RKValueTransformers.h \ No newline at end of file diff --git a/Pods/Headers/Public/RestKit/CoreData.h b/Pods/Headers/Public/RestKit/CoreData.h new file mode 120000 index 0000000..938f887 --- /dev/null +++ b/Pods/Headers/Public/RestKit/CoreData.h @@ -0,0 +1 @@ +../../../RestKit/Code/CoreData.h \ No newline at end of file diff --git a/Pods/Headers/Public/RestKit/CoreData/NSManagedObject+RKAdditions.h b/Pods/Headers/Public/RestKit/CoreData/NSManagedObject+RKAdditions.h new file mode 120000 index 0000000..bd245ec --- /dev/null +++ b/Pods/Headers/Public/RestKit/CoreData/NSManagedObject+RKAdditions.h @@ -0,0 +1 @@ +../../../../RestKit/Code/CoreData/NSManagedObject+RKAdditions.h \ No newline at end of file diff --git a/Pods/Headers/Public/RestKit/CoreData/NSManagedObjectContext+RKAdditions.h b/Pods/Headers/Public/RestKit/CoreData/NSManagedObjectContext+RKAdditions.h new file mode 120000 index 0000000..5129d8f --- /dev/null +++ b/Pods/Headers/Public/RestKit/CoreData/NSManagedObjectContext+RKAdditions.h @@ -0,0 +1 @@ +../../../../RestKit/Code/CoreData/NSManagedObjectContext+RKAdditions.h \ No newline at end of file diff --git a/Pods/Headers/Public/RestKit/CoreData/RKConnectionDescription.h b/Pods/Headers/Public/RestKit/CoreData/RKConnectionDescription.h new file mode 120000 index 0000000..ac38741 --- /dev/null +++ b/Pods/Headers/Public/RestKit/CoreData/RKConnectionDescription.h @@ -0,0 +1 @@ +../../../../RestKit/Code/CoreData/RKConnectionDescription.h \ No newline at end of file diff --git a/Pods/Headers/Public/RestKit/CoreData/RKCoreData.h b/Pods/Headers/Public/RestKit/CoreData/RKCoreData.h new file mode 120000 index 0000000..91d61b6 --- /dev/null +++ b/Pods/Headers/Public/RestKit/CoreData/RKCoreData.h @@ -0,0 +1 @@ +../../../../RestKit/Code/CoreData/RKCoreData.h \ No newline at end of file diff --git a/Pods/Headers/Public/RestKit/CoreData/RKEntityByAttributeCache.h b/Pods/Headers/Public/RestKit/CoreData/RKEntityByAttributeCache.h new file mode 120000 index 0000000..aabbe42 --- /dev/null +++ b/Pods/Headers/Public/RestKit/CoreData/RKEntityByAttributeCache.h @@ -0,0 +1 @@ +../../../../RestKit/Code/CoreData/RKEntityByAttributeCache.h \ No newline at end of file diff --git a/Pods/Headers/Public/RestKit/CoreData/RKEntityCache.h b/Pods/Headers/Public/RestKit/CoreData/RKEntityCache.h new file mode 120000 index 0000000..5e6d65d --- /dev/null +++ b/Pods/Headers/Public/RestKit/CoreData/RKEntityCache.h @@ -0,0 +1 @@ +../../../../RestKit/Code/CoreData/RKEntityCache.h \ No newline at end of file diff --git a/Pods/Headers/Public/RestKit/CoreData/RKEntityMapping.h b/Pods/Headers/Public/RestKit/CoreData/RKEntityMapping.h new file mode 120000 index 0000000..bf7a764 --- /dev/null +++ b/Pods/Headers/Public/RestKit/CoreData/RKEntityMapping.h @@ -0,0 +1 @@ +../../../../RestKit/Code/CoreData/RKEntityMapping.h \ No newline at end of file diff --git a/Pods/Headers/Public/RestKit/CoreData/RKFetchRequestManagedObjectCache.h b/Pods/Headers/Public/RestKit/CoreData/RKFetchRequestManagedObjectCache.h new file mode 120000 index 0000000..b71783d --- /dev/null +++ b/Pods/Headers/Public/RestKit/CoreData/RKFetchRequestManagedObjectCache.h @@ -0,0 +1 @@ +../../../../RestKit/Code/CoreData/RKFetchRequestManagedObjectCache.h \ No newline at end of file diff --git a/Pods/Headers/Public/RestKit/CoreData/RKInMemoryManagedObjectCache.h b/Pods/Headers/Public/RestKit/CoreData/RKInMemoryManagedObjectCache.h new file mode 120000 index 0000000..e133edd --- /dev/null +++ b/Pods/Headers/Public/RestKit/CoreData/RKInMemoryManagedObjectCache.h @@ -0,0 +1 @@ +../../../../RestKit/Code/CoreData/RKInMemoryManagedObjectCache.h \ No newline at end of file diff --git a/Pods/Headers/Public/RestKit/CoreData/RKManagedObjectCaching.h b/Pods/Headers/Public/RestKit/CoreData/RKManagedObjectCaching.h new file mode 120000 index 0000000..4850ebe --- /dev/null +++ b/Pods/Headers/Public/RestKit/CoreData/RKManagedObjectCaching.h @@ -0,0 +1 @@ +../../../../RestKit/Code/CoreData/RKManagedObjectCaching.h \ No newline at end of file diff --git a/Pods/Headers/Public/RestKit/CoreData/RKManagedObjectImporter.h b/Pods/Headers/Public/RestKit/CoreData/RKManagedObjectImporter.h new file mode 120000 index 0000000..895a95b --- /dev/null +++ b/Pods/Headers/Public/RestKit/CoreData/RKManagedObjectImporter.h @@ -0,0 +1 @@ +../../../../RestKit/Code/CoreData/RKManagedObjectImporter.h \ No newline at end of file diff --git a/Pods/Headers/Public/RestKit/CoreData/RKManagedObjectMappingOperationDataSource.h b/Pods/Headers/Public/RestKit/CoreData/RKManagedObjectMappingOperationDataSource.h new file mode 120000 index 0000000..63c21c8 --- /dev/null +++ b/Pods/Headers/Public/RestKit/CoreData/RKManagedObjectMappingOperationDataSource.h @@ -0,0 +1 @@ +../../../../RestKit/Code/CoreData/RKManagedObjectMappingOperationDataSource.h \ No newline at end of file diff --git a/Pods/Headers/Public/RestKit/CoreData/RKManagedObjectStore.h b/Pods/Headers/Public/RestKit/CoreData/RKManagedObjectStore.h new file mode 120000 index 0000000..c2abf47 --- /dev/null +++ b/Pods/Headers/Public/RestKit/CoreData/RKManagedObjectStore.h @@ -0,0 +1 @@ +../../../../RestKit/Code/CoreData/RKManagedObjectStore.h \ No newline at end of file diff --git a/Pods/Headers/Public/RestKit/CoreData/RKPropertyInspector+CoreData.h b/Pods/Headers/Public/RestKit/CoreData/RKPropertyInspector+CoreData.h new file mode 120000 index 0000000..9c57f2d --- /dev/null +++ b/Pods/Headers/Public/RestKit/CoreData/RKPropertyInspector+CoreData.h @@ -0,0 +1 @@ +../../../../RestKit/Code/CoreData/RKPropertyInspector+CoreData.h \ No newline at end of file diff --git a/Pods/Headers/Public/RestKit/CoreData/RKRelationshipConnectionOperation.h b/Pods/Headers/Public/RestKit/CoreData/RKRelationshipConnectionOperation.h new file mode 120000 index 0000000..80e3ca7 --- /dev/null +++ b/Pods/Headers/Public/RestKit/CoreData/RKRelationshipConnectionOperation.h @@ -0,0 +1 @@ +../../../../RestKit/Code/CoreData/RKRelationshipConnectionOperation.h \ No newline at end of file diff --git a/Pods/Headers/Public/RestKit/Network.h b/Pods/Headers/Public/RestKit/Network.h new file mode 120000 index 0000000..5210a78 --- /dev/null +++ b/Pods/Headers/Public/RestKit/Network.h @@ -0,0 +1 @@ +../../../RestKit/Code/Network.h \ No newline at end of file diff --git a/Pods/Headers/Public/RestKit/Network/RKHTTPRequestOperation.h b/Pods/Headers/Public/RestKit/Network/RKHTTPRequestOperation.h new file mode 120000 index 0000000..2b63c3c --- /dev/null +++ b/Pods/Headers/Public/RestKit/Network/RKHTTPRequestOperation.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Network/RKHTTPRequestOperation.h \ No newline at end of file diff --git a/Pods/Headers/Public/RestKit/Network/RKManagedObjectRequestOperation.h b/Pods/Headers/Public/RestKit/Network/RKManagedObjectRequestOperation.h new file mode 120000 index 0000000..c5f5677 --- /dev/null +++ b/Pods/Headers/Public/RestKit/Network/RKManagedObjectRequestOperation.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Network/RKManagedObjectRequestOperation.h \ No newline at end of file diff --git a/Pods/Headers/Public/RestKit/Network/RKObjectManager.h b/Pods/Headers/Public/RestKit/Network/RKObjectManager.h new file mode 120000 index 0000000..f67267f --- /dev/null +++ b/Pods/Headers/Public/RestKit/Network/RKObjectManager.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Network/RKObjectManager.h \ No newline at end of file diff --git a/Pods/Headers/Public/RestKit/Network/RKObjectParameterization.h b/Pods/Headers/Public/RestKit/Network/RKObjectParameterization.h new file mode 120000 index 0000000..73e232c --- /dev/null +++ b/Pods/Headers/Public/RestKit/Network/RKObjectParameterization.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Network/RKObjectParameterization.h \ No newline at end of file diff --git a/Pods/Headers/Public/RestKit/Network/RKObjectRequestOperation.h b/Pods/Headers/Public/RestKit/Network/RKObjectRequestOperation.h new file mode 120000 index 0000000..e4dbe06 --- /dev/null +++ b/Pods/Headers/Public/RestKit/Network/RKObjectRequestOperation.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Network/RKObjectRequestOperation.h \ No newline at end of file diff --git a/Pods/Headers/Public/RestKit/Network/RKObjectRequestOperationSubclass.h b/Pods/Headers/Public/RestKit/Network/RKObjectRequestOperationSubclass.h new file mode 120000 index 0000000..d0ca904 --- /dev/null +++ b/Pods/Headers/Public/RestKit/Network/RKObjectRequestOperationSubclass.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Network/RKObjectRequestOperationSubclass.h \ No newline at end of file diff --git a/Pods/Headers/Public/RestKit/Network/RKPaginator.h b/Pods/Headers/Public/RestKit/Network/RKPaginator.h new file mode 120000 index 0000000..35b421e --- /dev/null +++ b/Pods/Headers/Public/RestKit/Network/RKPaginator.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Network/RKPaginator.h \ No newline at end of file diff --git a/Pods/Headers/Public/RestKit/Network/RKPathMatcher.h b/Pods/Headers/Public/RestKit/Network/RKPathMatcher.h new file mode 120000 index 0000000..73ab1e6 --- /dev/null +++ b/Pods/Headers/Public/RestKit/Network/RKPathMatcher.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Network/RKPathMatcher.h \ No newline at end of file diff --git a/Pods/Headers/Public/RestKit/Network/RKRequestDescriptor.h b/Pods/Headers/Public/RestKit/Network/RKRequestDescriptor.h new file mode 120000 index 0000000..7f8e8b3 --- /dev/null +++ b/Pods/Headers/Public/RestKit/Network/RKRequestDescriptor.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Network/RKRequestDescriptor.h \ No newline at end of file diff --git a/Pods/Headers/Public/RestKit/Network/RKResponseDescriptor.h b/Pods/Headers/Public/RestKit/Network/RKResponseDescriptor.h new file mode 120000 index 0000000..4981d9a --- /dev/null +++ b/Pods/Headers/Public/RestKit/Network/RKResponseDescriptor.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Network/RKResponseDescriptor.h \ No newline at end of file diff --git a/Pods/Headers/Public/RestKit/Network/RKResponseMapperOperation.h b/Pods/Headers/Public/RestKit/Network/RKResponseMapperOperation.h new file mode 120000 index 0000000..a2e1586 --- /dev/null +++ b/Pods/Headers/Public/RestKit/Network/RKResponseMapperOperation.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Network/RKResponseMapperOperation.h \ No newline at end of file diff --git a/Pods/Headers/Public/RestKit/Network/RKRoute.h b/Pods/Headers/Public/RestKit/Network/RKRoute.h new file mode 120000 index 0000000..39eb2cb --- /dev/null +++ b/Pods/Headers/Public/RestKit/Network/RKRoute.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Network/RKRoute.h \ No newline at end of file diff --git a/Pods/Headers/Public/RestKit/Network/RKRouteSet.h b/Pods/Headers/Public/RestKit/Network/RKRouteSet.h new file mode 120000 index 0000000..a702bdc --- /dev/null +++ b/Pods/Headers/Public/RestKit/Network/RKRouteSet.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Network/RKRouteSet.h \ No newline at end of file diff --git a/Pods/Headers/Public/RestKit/Network/RKRouter.h b/Pods/Headers/Public/RestKit/Network/RKRouter.h new file mode 120000 index 0000000..7187f17 --- /dev/null +++ b/Pods/Headers/Public/RestKit/Network/RKRouter.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Network/RKRouter.h \ No newline at end of file diff --git a/Pods/Headers/Public/RestKit/ObjectMapping.h b/Pods/Headers/Public/RestKit/ObjectMapping.h new file mode 120000 index 0000000..9ca1b53 --- /dev/null +++ b/Pods/Headers/Public/RestKit/ObjectMapping.h @@ -0,0 +1 @@ +../../../RestKit/Code/ObjectMapping.h \ No newline at end of file diff --git a/Pods/Headers/Public/RestKit/ObjectMapping/RKAttributeMapping.h b/Pods/Headers/Public/RestKit/ObjectMapping/RKAttributeMapping.h new file mode 120000 index 0000000..b196d35 --- /dev/null +++ b/Pods/Headers/Public/RestKit/ObjectMapping/RKAttributeMapping.h @@ -0,0 +1 @@ +../../../../RestKit/Code/ObjectMapping/RKAttributeMapping.h \ No newline at end of file diff --git a/Pods/Headers/Public/RestKit/ObjectMapping/RKDynamicMapping.h b/Pods/Headers/Public/RestKit/ObjectMapping/RKDynamicMapping.h new file mode 120000 index 0000000..67a1caf --- /dev/null +++ b/Pods/Headers/Public/RestKit/ObjectMapping/RKDynamicMapping.h @@ -0,0 +1 @@ +../../../../RestKit/Code/ObjectMapping/RKDynamicMapping.h \ No newline at end of file diff --git a/Pods/Headers/Public/RestKit/ObjectMapping/RKErrorMessage.h b/Pods/Headers/Public/RestKit/ObjectMapping/RKErrorMessage.h new file mode 120000 index 0000000..6d6996d --- /dev/null +++ b/Pods/Headers/Public/RestKit/ObjectMapping/RKErrorMessage.h @@ -0,0 +1 @@ +../../../../RestKit/Code/ObjectMapping/RKErrorMessage.h \ No newline at end of file diff --git a/Pods/Headers/Public/RestKit/ObjectMapping/RKHTTPUtilities.h b/Pods/Headers/Public/RestKit/ObjectMapping/RKHTTPUtilities.h new file mode 120000 index 0000000..318d5c2 --- /dev/null +++ b/Pods/Headers/Public/RestKit/ObjectMapping/RKHTTPUtilities.h @@ -0,0 +1 @@ +../../../../RestKit/Code/ObjectMapping/RKHTTPUtilities.h \ No newline at end of file diff --git a/Pods/Headers/Public/RestKit/ObjectMapping/RKMapperOperation.h b/Pods/Headers/Public/RestKit/ObjectMapping/RKMapperOperation.h new file mode 120000 index 0000000..59e87e2 --- /dev/null +++ b/Pods/Headers/Public/RestKit/ObjectMapping/RKMapperOperation.h @@ -0,0 +1 @@ +../../../../RestKit/Code/ObjectMapping/RKMapperOperation.h \ No newline at end of file diff --git a/Pods/Headers/Public/RestKit/ObjectMapping/RKMapperOperation_Private.h b/Pods/Headers/Public/RestKit/ObjectMapping/RKMapperOperation_Private.h new file mode 120000 index 0000000..bd32976 --- /dev/null +++ b/Pods/Headers/Public/RestKit/ObjectMapping/RKMapperOperation_Private.h @@ -0,0 +1 @@ +../../../../RestKit/Code/ObjectMapping/RKMapperOperation_Private.h \ No newline at end of file diff --git a/Pods/Headers/Public/RestKit/ObjectMapping/RKMapping.h b/Pods/Headers/Public/RestKit/ObjectMapping/RKMapping.h new file mode 120000 index 0000000..6aaec37 --- /dev/null +++ b/Pods/Headers/Public/RestKit/ObjectMapping/RKMapping.h @@ -0,0 +1 @@ +../../../../RestKit/Code/ObjectMapping/RKMapping.h \ No newline at end of file diff --git a/Pods/Headers/Public/RestKit/ObjectMapping/RKMappingErrors.h b/Pods/Headers/Public/RestKit/ObjectMapping/RKMappingErrors.h new file mode 120000 index 0000000..68e3925 --- /dev/null +++ b/Pods/Headers/Public/RestKit/ObjectMapping/RKMappingErrors.h @@ -0,0 +1 @@ +../../../../RestKit/Code/ObjectMapping/RKMappingErrors.h \ No newline at end of file diff --git a/Pods/Headers/Public/RestKit/ObjectMapping/RKMappingOperation.h b/Pods/Headers/Public/RestKit/ObjectMapping/RKMappingOperation.h new file mode 120000 index 0000000..6b4d1bf --- /dev/null +++ b/Pods/Headers/Public/RestKit/ObjectMapping/RKMappingOperation.h @@ -0,0 +1 @@ +../../../../RestKit/Code/ObjectMapping/RKMappingOperation.h \ No newline at end of file diff --git a/Pods/Headers/Public/RestKit/ObjectMapping/RKMappingOperationDataSource.h b/Pods/Headers/Public/RestKit/ObjectMapping/RKMappingOperationDataSource.h new file mode 120000 index 0000000..d463834 --- /dev/null +++ b/Pods/Headers/Public/RestKit/ObjectMapping/RKMappingOperationDataSource.h @@ -0,0 +1 @@ +../../../../RestKit/Code/ObjectMapping/RKMappingOperationDataSource.h \ No newline at end of file diff --git a/Pods/Headers/Public/RestKit/ObjectMapping/RKMappingResult.h b/Pods/Headers/Public/RestKit/ObjectMapping/RKMappingResult.h new file mode 120000 index 0000000..03618d2 --- /dev/null +++ b/Pods/Headers/Public/RestKit/ObjectMapping/RKMappingResult.h @@ -0,0 +1 @@ +../../../../RestKit/Code/ObjectMapping/RKMappingResult.h \ No newline at end of file diff --git a/Pods/Headers/Public/RestKit/ObjectMapping/RKObjectMapping.h b/Pods/Headers/Public/RestKit/ObjectMapping/RKObjectMapping.h new file mode 120000 index 0000000..d38ebca --- /dev/null +++ b/Pods/Headers/Public/RestKit/ObjectMapping/RKObjectMapping.h @@ -0,0 +1 @@ +../../../../RestKit/Code/ObjectMapping/RKObjectMapping.h \ No newline at end of file diff --git a/Pods/Headers/Public/RestKit/ObjectMapping/RKObjectMappingMatcher.h b/Pods/Headers/Public/RestKit/ObjectMapping/RKObjectMappingMatcher.h new file mode 120000 index 0000000..2664bd7 --- /dev/null +++ b/Pods/Headers/Public/RestKit/ObjectMapping/RKObjectMappingMatcher.h @@ -0,0 +1 @@ +../../../../RestKit/Code/ObjectMapping/RKObjectMappingMatcher.h \ No newline at end of file diff --git a/Pods/Headers/Public/RestKit/ObjectMapping/RKObjectMappingOperationDataSource.h b/Pods/Headers/Public/RestKit/ObjectMapping/RKObjectMappingOperationDataSource.h new file mode 120000 index 0000000..cdac049 --- /dev/null +++ b/Pods/Headers/Public/RestKit/ObjectMapping/RKObjectMappingOperationDataSource.h @@ -0,0 +1 @@ +../../../../RestKit/Code/ObjectMapping/RKObjectMappingOperationDataSource.h \ No newline at end of file diff --git a/Pods/Headers/Public/RestKit/ObjectMapping/RKObjectUtilities.h b/Pods/Headers/Public/RestKit/ObjectMapping/RKObjectUtilities.h new file mode 120000 index 0000000..1ee01f3 --- /dev/null +++ b/Pods/Headers/Public/RestKit/ObjectMapping/RKObjectUtilities.h @@ -0,0 +1 @@ +../../../../RestKit/Code/ObjectMapping/RKObjectUtilities.h \ No newline at end of file diff --git a/Pods/Headers/Public/RestKit/ObjectMapping/RKPropertyInspector.h b/Pods/Headers/Public/RestKit/ObjectMapping/RKPropertyInspector.h new file mode 120000 index 0000000..a3e2a9d --- /dev/null +++ b/Pods/Headers/Public/RestKit/ObjectMapping/RKPropertyInspector.h @@ -0,0 +1 @@ +../../../../RestKit/Code/ObjectMapping/RKPropertyInspector.h \ No newline at end of file diff --git a/Pods/Headers/Public/RestKit/ObjectMapping/RKPropertyMapping.h b/Pods/Headers/Public/RestKit/ObjectMapping/RKPropertyMapping.h new file mode 120000 index 0000000..db4bc5c --- /dev/null +++ b/Pods/Headers/Public/RestKit/ObjectMapping/RKPropertyMapping.h @@ -0,0 +1 @@ +../../../../RestKit/Code/ObjectMapping/RKPropertyMapping.h \ No newline at end of file diff --git a/Pods/Headers/Public/RestKit/ObjectMapping/RKRelationshipMapping.h b/Pods/Headers/Public/RestKit/ObjectMapping/RKRelationshipMapping.h new file mode 120000 index 0000000..32b9847 --- /dev/null +++ b/Pods/Headers/Public/RestKit/ObjectMapping/RKRelationshipMapping.h @@ -0,0 +1 @@ +../../../../RestKit/Code/ObjectMapping/RKRelationshipMapping.h \ No newline at end of file diff --git a/Pods/Headers/Public/RestKit/RestKit.h b/Pods/Headers/Public/RestKit/RestKit.h new file mode 120000 index 0000000..49e183c --- /dev/null +++ b/Pods/Headers/Public/RestKit/RestKit.h @@ -0,0 +1 @@ +../../../RestKit/Code/RestKit.h \ No newline at end of file diff --git a/Pods/Headers/Public/RestKit/Support.h b/Pods/Headers/Public/RestKit/Support.h new file mode 120000 index 0000000..06fa6db --- /dev/null +++ b/Pods/Headers/Public/RestKit/Support.h @@ -0,0 +1 @@ +../../../RestKit/Code/Support.h \ No newline at end of file diff --git a/Pods/Headers/Public/RestKit/Support/RKDictionaryUtilities.h b/Pods/Headers/Public/RestKit/Support/RKDictionaryUtilities.h new file mode 120000 index 0000000..f4e0175 --- /dev/null +++ b/Pods/Headers/Public/RestKit/Support/RKDictionaryUtilities.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Support/RKDictionaryUtilities.h \ No newline at end of file diff --git a/Pods/Headers/Public/RestKit/Support/RKDotNetDateFormatter.h b/Pods/Headers/Public/RestKit/Support/RKDotNetDateFormatter.h new file mode 120000 index 0000000..44ee028 --- /dev/null +++ b/Pods/Headers/Public/RestKit/Support/RKDotNetDateFormatter.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Support/RKDotNetDateFormatter.h \ No newline at end of file diff --git a/Pods/Headers/Public/RestKit/Support/RKErrors.h b/Pods/Headers/Public/RestKit/Support/RKErrors.h new file mode 120000 index 0000000..7319216 --- /dev/null +++ b/Pods/Headers/Public/RestKit/Support/RKErrors.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Support/RKErrors.h \ No newline at end of file diff --git a/Pods/Headers/Public/RestKit/Support/RKLog.h b/Pods/Headers/Public/RestKit/Support/RKLog.h new file mode 120000 index 0000000..6a428cb --- /dev/null +++ b/Pods/Headers/Public/RestKit/Support/RKLog.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Support/RKLog.h \ No newline at end of file diff --git a/Pods/Headers/Public/RestKit/Support/RKLumberjackLogger.h b/Pods/Headers/Public/RestKit/Support/RKLumberjackLogger.h new file mode 120000 index 0000000..b8d134c --- /dev/null +++ b/Pods/Headers/Public/RestKit/Support/RKLumberjackLogger.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Support/RKLumberjackLogger.h \ No newline at end of file diff --git a/Pods/Headers/Public/RestKit/Support/RKMIMETypeSerialization.h b/Pods/Headers/Public/RestKit/Support/RKMIMETypeSerialization.h new file mode 120000 index 0000000..b77b8b3 --- /dev/null +++ b/Pods/Headers/Public/RestKit/Support/RKMIMETypeSerialization.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Support/RKMIMETypeSerialization.h \ No newline at end of file diff --git a/Pods/Headers/Public/RestKit/Support/RKMIMETypes.h b/Pods/Headers/Public/RestKit/Support/RKMIMETypes.h new file mode 120000 index 0000000..71b36c8 --- /dev/null +++ b/Pods/Headers/Public/RestKit/Support/RKMIMETypes.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Support/RKMIMETypes.h \ No newline at end of file diff --git a/Pods/Headers/Public/RestKit/Support/RKMacros.h b/Pods/Headers/Public/RestKit/Support/RKMacros.h new file mode 120000 index 0000000..f1d842d --- /dev/null +++ b/Pods/Headers/Public/RestKit/Support/RKMacros.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Support/RKMacros.h \ No newline at end of file diff --git a/Pods/Headers/Public/RestKit/Support/RKNSJSONSerialization.h b/Pods/Headers/Public/RestKit/Support/RKNSJSONSerialization.h new file mode 120000 index 0000000..537580d --- /dev/null +++ b/Pods/Headers/Public/RestKit/Support/RKNSJSONSerialization.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Support/RKNSJSONSerialization.h \ No newline at end of file diff --git a/Pods/Headers/Public/RestKit/Support/RKOperationStateMachine.h b/Pods/Headers/Public/RestKit/Support/RKOperationStateMachine.h new file mode 120000 index 0000000..1391329 --- /dev/null +++ b/Pods/Headers/Public/RestKit/Support/RKOperationStateMachine.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Support/RKOperationStateMachine.h \ No newline at end of file diff --git a/Pods/Headers/Public/RestKit/Support/RKPathUtilities.h b/Pods/Headers/Public/RestKit/Support/RKPathUtilities.h new file mode 120000 index 0000000..2ef3a20 --- /dev/null +++ b/Pods/Headers/Public/RestKit/Support/RKPathUtilities.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Support/RKPathUtilities.h \ No newline at end of file diff --git a/Pods/Headers/Public/RestKit/Support/RKSerialization.h b/Pods/Headers/Public/RestKit/Support/RKSerialization.h new file mode 120000 index 0000000..b66ce92 --- /dev/null +++ b/Pods/Headers/Public/RestKit/Support/RKSerialization.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Support/RKSerialization.h \ No newline at end of file diff --git a/Pods/Headers/Public/RestKit/Support/RKStringTokenizer.h b/Pods/Headers/Public/RestKit/Support/RKStringTokenizer.h new file mode 120000 index 0000000..6535c08 --- /dev/null +++ b/Pods/Headers/Public/RestKit/Support/RKStringTokenizer.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Support/RKStringTokenizer.h \ No newline at end of file diff --git a/Pods/Headers/Public/RestKit/Support/RKURLEncodedSerialization.h b/Pods/Headers/Public/RestKit/Support/RKURLEncodedSerialization.h new file mode 120000 index 0000000..ea62327 --- /dev/null +++ b/Pods/Headers/Public/RestKit/Support/RKURLEncodedSerialization.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Support/RKURLEncodedSerialization.h \ No newline at end of file diff --git a/Pods/Headers/Public/RestKit/Support/lcl_config_components_RK.h b/Pods/Headers/Public/RestKit/Support/lcl_config_components_RK.h new file mode 120000 index 0000000..7902c5b --- /dev/null +++ b/Pods/Headers/Public/RestKit/Support/lcl_config_components_RK.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Support/lcl_config_components_RK.h \ No newline at end of file diff --git a/Pods/Headers/Public/RestKit/Support/lcl_config_extensions_RK.h b/Pods/Headers/Public/RestKit/Support/lcl_config_extensions_RK.h new file mode 120000 index 0000000..eff8ca5 --- /dev/null +++ b/Pods/Headers/Public/RestKit/Support/lcl_config_extensions_RK.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Support/lcl_config_extensions_RK.h \ No newline at end of file diff --git a/Pods/Headers/Public/RestKit/Support/lcl_config_logger_RK.h b/Pods/Headers/Public/RestKit/Support/lcl_config_logger_RK.h new file mode 120000 index 0000000..39088b8 --- /dev/null +++ b/Pods/Headers/Public/RestKit/Support/lcl_config_logger_RK.h @@ -0,0 +1 @@ +../../../../RestKit/Code/Support/lcl_config_logger_RK.h \ No newline at end of file diff --git a/Pods/Headers/Public/SOCKit/SOCKit.h b/Pods/Headers/Public/SOCKit/SOCKit.h new file mode 120000 index 0000000..72c5afc --- /dev/null +++ b/Pods/Headers/Public/SOCKit/SOCKit.h @@ -0,0 +1 @@ +../../../SOCKit/SOCKit.h \ No newline at end of file diff --git a/Pods/Headers/Public/TransitionKit/TKEvent.h b/Pods/Headers/Public/TransitionKit/TKEvent.h new file mode 120000 index 0000000..e0febb8 --- /dev/null +++ b/Pods/Headers/Public/TransitionKit/TKEvent.h @@ -0,0 +1 @@ +../../../TransitionKit/Code/TKEvent.h \ No newline at end of file diff --git a/Pods/Headers/Public/TransitionKit/TKState.h b/Pods/Headers/Public/TransitionKit/TKState.h new file mode 120000 index 0000000..6dbd8d3 --- /dev/null +++ b/Pods/Headers/Public/TransitionKit/TKState.h @@ -0,0 +1 @@ +../../../TransitionKit/Code/TKState.h \ No newline at end of file diff --git a/Pods/Headers/Public/TransitionKit/TKStateMachine.h b/Pods/Headers/Public/TransitionKit/TKStateMachine.h new file mode 120000 index 0000000..cfbbd7f --- /dev/null +++ b/Pods/Headers/Public/TransitionKit/TKStateMachine.h @@ -0,0 +1 @@ +../../../TransitionKit/Code/TKStateMachine.h \ No newline at end of file diff --git a/Pods/Headers/Public/TransitionKit/TKTransition.h b/Pods/Headers/Public/TransitionKit/TKTransition.h new file mode 120000 index 0000000..d83dc2c --- /dev/null +++ b/Pods/Headers/Public/TransitionKit/TKTransition.h @@ -0,0 +1 @@ +../../../TransitionKit/Code/TKTransition.h \ No newline at end of file diff --git a/Pods/Headers/Public/TransitionKit/TransitionKit.h b/Pods/Headers/Public/TransitionKit/TransitionKit.h new file mode 120000 index 0000000..d5b6768 --- /dev/null +++ b/Pods/Headers/Public/TransitionKit/TransitionKit.h @@ -0,0 +1 @@ +../../../TransitionKit/Code/TransitionKit.h \ No newline at end of file diff --git a/Pods/Headers/Public/Vendor/LibComponentLogging/Core/lcl_RK.h b/Pods/Headers/Public/Vendor/LibComponentLogging/Core/lcl_RK.h new file mode 120000 index 0000000..d94e2d3 --- /dev/null +++ b/Pods/Headers/Public/Vendor/LibComponentLogging/Core/lcl_RK.h @@ -0,0 +1 @@ +../../../../../RestKit/Vendor/LibComponentLogging/Core/lcl_RK.h \ No newline at end of file diff --git a/Pods/ISO8601DateFormatterValueTransformer/Code/ISO8601DateFormatterValueTransformer.h b/Pods/ISO8601DateFormatterValueTransformer/Code/ISO8601DateFormatterValueTransformer.h new file mode 100644 index 0000000..7a758e4 --- /dev/null +++ b/Pods/ISO8601DateFormatterValueTransformer/Code/ISO8601DateFormatterValueTransformer.h @@ -0,0 +1,34 @@ +// +// ISO8601DateFormatterValueTransformer.h +// RestKit +// +// Created by Blake Watters on 9/11/13. +// Copyright (c) 2013 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKValueTransformers.h" +#import "RKISO8601DateFormatter.h" + +/** + The `RKValueTransformers` category extends ISO8601DateFormatter to support the `RKValueTransforming` interface, making it usable with the RestKit value transformation architecture. + */ +@interface RKISO8601DateFormatter (RKValueTransformers) + +/** + Returns an ISO 8601 date formatter configured to strictly parse times into `NSDate` instances with the UTC time zone and `en_US_POSIX` locale. + */ ++ (instancetype)defaultISO8601DateFormatter; + +@end diff --git a/Pods/ISO8601DateFormatterValueTransformer/Code/ISO8601DateFormatterValueTransformer.m b/Pods/ISO8601DateFormatterValueTransformer/Code/ISO8601DateFormatterValueTransformer.m new file mode 100644 index 0000000..fd42686 --- /dev/null +++ b/Pods/ISO8601DateFormatterValueTransformer/Code/ISO8601DateFormatterValueTransformer.m @@ -0,0 +1,55 @@ +// +// ISO8601DateFormatterValueTransformer.m +// RestKit +// +// Created by Blake Watters on 9/11/13. +// Copyright (c) 2013 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "ISO8601DateFormatterValueTransformer.h" + +@implementation RKISO8601DateFormatter (RKValueTransformers) + ++ (instancetype)defaultISO8601DateFormatter +{ + RKISO8601DateFormatter *iso8601DateFormatter = [RKISO8601DateFormatter new]; + iso8601DateFormatter.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"UTC"]; + iso8601DateFormatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"]; + iso8601DateFormatter.includeTime = YES; + iso8601DateFormatter.parsesStrictly = YES; + return iso8601DateFormatter; +} + +- (BOOL)validateTransformationFromClass:(Class)inputValueClass toClass:(Class)outputValueClass +{ + return (([inputValueClass isSubclassOfClass:[NSDate class]] && [outputValueClass isSubclassOfClass:[NSString class]]) || + ([inputValueClass isSubclassOfClass:[NSString class]] && [outputValueClass isSubclassOfClass:[NSDate class]])); +} + +- (BOOL)transformValue:(id)inputValue toValue:(id *)outputValue ofClass:(Class)outputValueClass error:(NSError **)error +{ + RKValueTransformerTestInputValueIsKindOfClass(inputValue, (@[ [NSString class], [NSDate class] ]), error); + RKValueTransformerTestOutputValueClassIsSubclassOfClass(outputValueClass, (@[ [NSString class], [NSDate class] ]), error); + if ([inputValue isKindOfClass:[NSString class]]) { + NSString *errorDescription = nil; + BOOL success = [self getObjectValue:outputValue forString:inputValue errorDescription:&errorDescription]; + RKValueTransformerTestTransformation(success, error, @"%@", errorDescription); + } else if ([inputValue isKindOfClass:[NSDate class]]) { + *outputValue = [self stringFromDate:inputValue]; + } + return YES; +} + +@end diff --git a/Pods/ISO8601DateFormatterValueTransformer/Code/RKISO8601DateFormatter.h b/Pods/ISO8601DateFormatterValueTransformer/Code/RKISO8601DateFormatter.h new file mode 100644 index 0000000..f4cc12a --- /dev/null +++ b/Pods/ISO8601DateFormatterValueTransformer/Code/RKISO8601DateFormatter.h @@ -0,0 +1,93 @@ +// This is a forked copy of the ISO8601DateFormatter + +/*ISO8601DateFormatter.h + * + *Created by Peter Hosey on 2009-04-11. + *Copyright 2009 Peter Hosey. All rights reserved. + */ + +#import + +/*This class converts dates to and from ISO 8601 strings. A good introduction to ISO 8601: + * + *Parsing can be done strictly, or not. When you parse loosely, leading whitespace is ignored, as is anything after the date. + *The loose parser will return an NSDate for this string: @" \t\r\n\f\t 2006-03-02!!!" + *Leading non-whitespace will not be ignored; the string will be rejected, and nil returned. See the README that came with this addition. + * + *The strict parser will only accept a string if the date is the entire string. The above string would be rejected immediately, solely on these grounds. + *Also, the loose parser provides some extensions that the strict parser doesn't. + *For example, the standard says for "-DDD" (an ordinal date in the implied year) that the logical representation (meaning, hierarchically) would be "--DDD", but because that extra hyphen is "superfluous", it was omitted. + *The loose parser will accept the extra hyphen; the strict parser will not. + *A full list of these extensions is in the README file. + */ + +/*The format to either expect or produce. + *Calendar format is YYYY-MM-DD. + *Ordinal format is YYYY-DDD, where DDD ranges from 1 to 366; for example, 2009-32 is 2009-02-01. + *Week format is YYYY-Www-D, where ww ranges from 1 to 53 (the 'W' is literal) and D ranges from 1 to 7; for example, 2009-W05-07. + */ +enum { + RKISO8601DateFormatCalendar, + RKISO8601DateFormatOrdinal, + RKISO8601DateFormatWeek, +}; +typedef NSUInteger RKISO8601DateFormat; + +@interface RKISO8601DateFormatter: NSFormatter + +/** + The time zone for tge formatter. + + **Default:** `[NSTimeZone defaultTimeZone]` + */ +@property (nonatomic, strong) NSTimeZone *timeZone; + +/** + The locale for the formatter. + + **Default:** `[NSLocale currentLocale]` + */ +@property (nonatomic, strong) NSLocale *locale; + +#pragma mark Parsing + +/** + A Boolean value that determines if the receiver parses strictly. + + **Default**: `NO` + */ +@property (nonatomic, assign) BOOL parsesStrictly; + +- (NSDateComponents *)dateComponentsFromString:(NSString *)string; +- (NSDate *)dateFromString:(NSString *)string; + +#pragma mark Unparsing + +/** + **Default**: `RKISO8601DateFormatCalendar` + */ +@property (nonatomic, assign) RKISO8601DateFormat format; + +/** + A Boolean value that specifies if time should be included in the formatted strings. + + **Default**: `NO` + */ +@property (nonatomic, assign) BOOL includeTime; + +/** + The separator character to use between time components. + + **Default**: `':'` + */ +@property (nonatomic, assign) unichar timeSeparator; + +/** + Returns an ISO-8601 string representation of the given date. + + @param date The date to be formatted into a string. + @return An ISO-8601 formatted string representation of the date. + */ +- (NSString *)stringFromDate:(NSDate *)date; + +@end diff --git a/Pods/ISO8601DateFormatterValueTransformer/Code/RKISO8601DateFormatter.m b/Pods/ISO8601DateFormatterValueTransformer/Code/RKISO8601DateFormatter.m new file mode 100644 index 0000000..2079593 --- /dev/null +++ b/Pods/ISO8601DateFormatterValueTransformer/Code/RKISO8601DateFormatter.m @@ -0,0 +1,912 @@ +// This is a forked copy of the ISO8601DateFormatter + +/*ISO8601DateFormatter.m + * + *Created by Peter Hosey on 2009-04-11. + *Copyright 2009 Peter Hosey. All rights reserved. + */ + +#import +#import "RKISO8601DateFormatter.h" + +// Set Logging Component +#undef RKLogComponent +#define RKLogComponent RKlcl_cRestKitSupport + +unichar RKISO8601DefaultTimeSeparatorCharacter = ':'; + +// Unicode date formats. +#define RK_ISOCALENDAR_DATE_FORMAT @"yyyy-MM-dd" +#define RK_ISOORDINAL_DATE_FORMAT @"yyyy-DDD" +#define RK_ISOTIME_FORMAT @"HH:mm:ss" +#define RK_ISOTIME_WITH_TIMEZONE_FORMAT RK_ISOTIME_FORMAT @"Z" + +// printf formats. +#define RK_ISOTIMEZONE_UTC_FORMAT @"Z" +#define RK_ISOTIMEZONE_OFFSET_FORMAT @"%+.2ld%.2ld" + +#if (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && (__IPHONE_OS_VERSION_MAX_ALLOWED < 70000)) || \ + (defined(MAC_OS_X_VERSION_MAX_ALLOWED) && (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_9)) +#define NSCalendarUnitYear NSYearCalendarUnit +#define NSCalendarUnitMonth NSMonthCalendarUnit +#define NSCalendarUnitDay NSDayCalendarUnit +#define NSCalendarUnitWeekday NSWeekdayCalendarUnit +#define NSCalendarIdentifierGregorian NSGregorianCalendar +#endif + +#define RK_CALENDAR_UNIT_YEAR NSCalendarUnitYear +#define RK_CALENDAR_UNIT_MONTH NSCalendarUnitMonth +#define RK_CALENDAR_UNIT_DAY NSCalendarUnitDay +#define RK_CALENDAR_UNIT_WEEKDAY NSCalendarUnitWeekday +#define RK_CALENDAR_IDENTIFIER_GREGORIAN NSCalendarIdentifierGregorian + +// Parsing Helpers +static NSUInteger read_segment(const unsigned char *str, const unsigned char **next, NSUInteger *out_num_digits); +static NSUInteger read_segment_4digits(const unsigned char *str, const unsigned char **next, NSUInteger *out_num_digits); +static NSUInteger read_segment_2digits(const unsigned char *str, const unsigned char **next); +static double read_double(const unsigned char *str, const unsigned char **next); +static BOOL is_leap_year(NSUInteger year); + +@interface RKISO8601DateFormatter(UnparsingPrivate) + +- (NSString *)replaceColonsInString:(NSString *)timeFormat withTimeSeparator:(unichar)timeSep; +- (NSString *)stringFromDate:(NSDate *)date formatString:(NSString *)dateFormat timeZone:(NSTimeZone *)timeZone; +- (NSString *)weekDateStringForDate:(NSDate *)date timeZone:(NSTimeZone *)timeZone; + +@end + +static NSMutableDictionary *timeZonesByOffset; + +@interface RKISO8601DateFormatter () +@property (nonatomic, strong) NSCalendar *parsingCalendar; +@property (nonatomic, strong) NSCalendar *unparsingCalendar; +@property (nonatomic, strong) NSDateFormatter *unparsingFormatter; +@property (nonatomic, copy) NSString *lastUsedFormatString; +@end + +@implementation RKISO8601DateFormatter + ++ (void)initialize +{ + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + timeZonesByOffset = [[NSMutableDictionary alloc] init]; + }); +} + +- (id)init +{ + self = [super init]; + if (self) { + self.timeZone = [NSTimeZone defaultTimeZone]; + self.locale = [NSLocale currentLocale]; + + self.parsingCalendar = [self newCalendar]; + self.unparsingCalendar = [self newCalendar]; + + self.format = RKISO8601DateFormatCalendar; + self.timeSeparator = RKISO8601DefaultTimeSeparatorCharacter; + self.includeTime = NO; + self.parsesStrictly = NO; + } + return self; +} + +- (NSCalendar *)newCalendar +{ + NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:RK_CALENDAR_IDENTIFIER_GREGORIAN]; + calendar.firstWeekday = 2; //Monday + calendar.timeZone = self.timeZone; + calendar.locale = self.locale; + return calendar; +} + +- (void)setTimeZone:(NSTimeZone *)timeZone +{ + if (_timeZone != timeZone) { + _timeZone = timeZone; + _unparsingCalendar.timeZone = timeZone; + _unparsingFormatter.timeZone = timeZone; + } +} + +- (void)setLocale:(NSLocale *)locale +{ + if (_locale != locale) { + _locale = locale; + _unparsingCalendar.locale = locale; + _unparsingFormatter.locale = locale; + } +} + +#pragma mark Parsing + +/*Valid ISO 8601 date formats: + * + *YYYYMMDD + *YYYY-MM-DD + *YYYY-MM + *YYYY + *YY //century + * //Implied century: YY is 00-99 + * YYMMDD + * YY-MM-DD + * -YYMM + * -YY-MM + * -YY + * //Implied year + * --MMDD + * --MM-DD + * --MM + * //Implied year and month + * ---DD + * //Ordinal dates: DDD is the number of the day in the year (1-366) + *YYYYDDD + *YYYY-DDD + * YYDDD + * YY-DDD + * -DDD + * //Week-based dates: ww is the number of the week, and d is the number (1-7) of the day in the week + *yyyyWwwd + *yyyy-Www-d + *yyyyWww + *yyyy-Www + *yyWwwd + *yy-Www-d + *yyWww + *yy-Www + * //Year of the implied decade + *-yWwwd + *-y-Www-d + *-yWww + *-y-Www + * //Week and day of implied year + * -Wwwd + * -Www-d + * //Week only of implied year + * -Www + * //Day only of implied week + * -W-d + */ + +- (NSDateComponents *) dateComponentsFromString:(NSString *)string +{ + return [self dateComponentsFromString:string timeZone:NULL]; +} + +- (NSDateComponents *) dateComponentsFromString:(NSString *)string timeZone:(out NSTimeZone **)outTimeZone +{ + return [self dateComponentsFromString:string timeZone:outTimeZone range:NULL]; +} + +- (NSDateComponents *) dateComponentsFromString:(NSString *)string timeZone:(out NSTimeZone **)outTimeZone range:(out NSRange *)outRange +{ + // We don't support ISO-8601 intervals so bail if the string contains a slash delimiter + if ([string rangeOfCharacterFromSet:[NSCharacterSet characterSetWithCharactersInString:@"/"]].location != NSNotFound) return nil; + + NSDate *now = [NSDate date]; + + NSDateComponents *components = [[NSDateComponents alloc] init]; + NSDateComponents *nowComponents = [self.parsingCalendar components:(RK_CALENDAR_UNIT_YEAR | RK_CALENDAR_UNIT_MONTH | RK_CALENDAR_UNIT_DAY) fromDate:now]; + + NSUInteger + //Date + year, + month_or_week = 0U, + day = 0U, + //Time + hour = 0U; + NSTimeInterval + minute = 0.0, + second = 0.0; + //Time zone + NSInteger tz_hour = 0; + NSInteger tz_minute = 0; + + enum { + monthAndDate, + week, + dateOnly + } dateSpecification = monthAndDate; + + BOOL strict = self.parsesStrictly; + unichar timeSep = self.timeSeparator; + + if (strict) timeSep = RKISO8601DefaultTimeSeparatorCharacter; + NSAssert(timeSep != '\0', @"Time separator must not be NUL."); + + BOOL isValidDate = ([string length] > 0U); + NSTimeZone *timeZone = nil; + + const unsigned char *ch = (const unsigned char *)[string UTF8String]; + + NSRange range = { 0U, 0U }; + const unsigned char *start_of_date = NULL; + if (strict && isspace(*ch)) { + range.location = NSNotFound; + isValidDate = NO; + } else { + //Skip leading whitespace. + NSUInteger i = 0U; + for(NSUInteger len = strlen((const char *)ch); i < len; ++i) { + if (!isspace(ch[i])) + break; + } + + range.location = i; + ch += i; + start_of_date = ch; + + NSUInteger segment; + NSUInteger num_leading_hyphens = 0U, num_digits = 0U; + + if (*ch == 'T') { + //There is no date here, only a time. Set the date to now; then we'll parse the time. + isValidDate = isdigit(*++ch); + + year = nowComponents.year; + month_or_week = nowComponents.month; + day = nowComponents.day; + } else { + while(*ch == '-') { + ++num_leading_hyphens; + ++ch; + } + + segment = read_segment(ch, &ch, &num_digits); + switch(num_digits) { + case 0: + if (*ch == 'W') { + if ((ch[1] == '-') && isdigit(ch[2]) && ((num_leading_hyphens == 1U) || ((num_leading_hyphens == 2U) && !strict))) { + year = nowComponents.year; + month_or_week = 1U; + ch += 2; + goto parseDayAfterWeek; + } else if (num_leading_hyphens == 1U) { + year = nowComponents.year; + goto parseWeekAndDay; + } else + isValidDate = NO; + } else + isValidDate = NO; + break; + + case 8: //YYYY MM DD + if (num_leading_hyphens > 0U) + isValidDate = NO; + else { + day = segment % 100U; + segment /= 100U; + month_or_week = segment % 100U; + year = segment / 100U; + } + break; + + case 6: //YYMMDD (implicit century) + if (num_leading_hyphens > 0U) + isValidDate = NO; + else { + day = segment % 100U; + segment /= 100U; + month_or_week = segment % 100U; + year = nowComponents.year; + year -= (year % 100U); + year += segment / 100U; + } + break; + + case 4: + switch(num_leading_hyphens) { + case 0: //YYYY + year = segment; + + if (*ch == '-') ++ch; + + if (!isdigit(*ch)) { + if (*ch == 'W') + goto parseWeekAndDay; + else + month_or_week = day = 1U; + } else { + segment = read_segment(ch, &ch, &num_digits); + switch(num_digits) { + case 4: //MMDD + day = segment % 100U; + month_or_week = segment / 100U; + break; + + case 2: //MM + month_or_week = segment; + + if (*ch == '-') ++ch; + if (!isdigit(*ch)) + day = 1U; + else + day = read_segment(ch, &ch, NULL); + break; + + case 3: //DDD + day = segment % 1000U; + dateSpecification = dateOnly; + if (strict && (day > (365U + is_leap_year(year)))) + isValidDate = NO; + break; + + default: + isValidDate = NO; + } + } + break; + + case 1: //YYMM + month_or_week = segment % 100U; + year = segment / 100U; + + if (*ch == '-') ++ch; + if (!isdigit(*ch)) + day = 1U; + else + day = read_segment(ch, &ch, NULL); + + break; + + case 2: //MMDD + day = segment % 100U; + month_or_week = segment / 100U; + year = nowComponents.year; + + break; + + default: + isValidDate = NO; + } //switch(num_leading_hyphens) (4 digits) + break; + + case 1: + if (strict) { + //Two digits only - never just one. + if (num_leading_hyphens == 1U) { + if (*ch == '-') ++ch; + if (*++ch == 'W') { + year = nowComponents.year; + year -= (year % 10U); + year += segment; + goto parseWeekAndDay; + } else + isValidDate = NO; + } else + isValidDate = NO; + break; + } + case 2: + switch(num_leading_hyphens) { + case 0: + if (*ch == '-') { + //Implicit century + year = nowComponents.year; + year -= (year % 100U); + year += segment; + + if (*++ch == 'W') + goto parseWeekAndDay; + else if (!isdigit(*ch)) { + goto centuryOnly; + } else { + //Get month and/or date. + segment = read_segment_4digits(ch, &ch, &num_digits); + switch(num_digits) { + case 4: //YY-MMDD + day = segment % 100U; + month_or_week = segment / 100U; + break; + + case 1: //YY-M; YY-M-DD (extension) + if (strict) { + isValidDate = NO; + break; + } + case 2: //YY-MM; YY-MM-DD + month_or_week = segment; + if (*ch == '-') { + if (isdigit(*++ch)) + day = read_segment_2digits(ch, &ch); + else + day = 1U; + } else + day = 1U; + break; + + case 3: //Ordinal date. + day = segment; + dateSpecification = dateOnly; + break; + } + } + } else if (*ch == 'W') { + year = nowComponents.year; + year -= (year % 100U); + year += segment; + + parseWeekAndDay: //*ch should be 'W' here. + if (!isdigit(*++ch)) { + //Not really a week-based date; just a year followed by '-W'. + if (strict) + isValidDate = NO; + else + month_or_week = day = 1U; + } else { + month_or_week = read_segment_2digits(ch, &ch); + if (*ch == '-') ++ch; + parseDayAfterWeek: + day = isdigit(*ch) ? read_segment_2digits(ch, &ch) : 1U; + dateSpecification = week; + } + } else { + //Century only. Assume current year. + centuryOnly: + year = segment * 100U + nowComponents.year % 100U; + month_or_week = day = 1U; + } + break; + + case 1:; //-YY; -YY-MM (implicit century) + NSUInteger current_year = nowComponents.year; + NSUInteger current_century = (current_year % 100U); + year = segment + (current_year - current_century); + if (num_digits == 1U) //implied decade + year += current_century - (current_year % 10U); + + if (*ch == '-') { + ++ch; + month_or_week = read_segment_2digits(ch, &ch); + } + + day = 1U; + break; + + case 2: //--MM; --MM-DD + year = nowComponents.year; + month_or_week = segment; + if (*ch == '-') { + ++ch; + day = read_segment_2digits(ch, &ch); + } + break; + + case 3: //---DD + year = nowComponents.year; + month_or_week = nowComponents.month; + day = segment; + break; + + default: + isValidDate = NO; + } //switch(num_leading_hyphens) (2 digits) + break; + + case 7: //YYYY DDD (ordinal date) + if (num_leading_hyphens > 0U) + isValidDate = NO; + else { + day = segment % 1000U; + year = segment / 1000U; + dateSpecification = dateOnly; + if (strict && (day > (365U + is_leap_year(year)))) + isValidDate = NO; + } + break; + + case 3: //--DDD (ordinal date, implicit year) + //Technically, the standard only allows one hyphen. But it says that two hyphens is the logical implementation, and one was dropped for brevity. So I have chosen to allow the missing hyphen. + if ((num_leading_hyphens < 1U) || ((num_leading_hyphens > 2U) && !strict)) + isValidDate = NO; + else { + day = segment; + year = nowComponents.year; + dateSpecification = dateOnly; + if (strict && (day > (365U + is_leap_year(year)))) + isValidDate = NO; + } + break; + + default: + isValidDate = NO; + } + } + + if (isValidDate) { + if (isspace(*ch) || (*ch == 'T')) ++ch; + + if (isdigit(*ch)) { + hour = read_segment_2digits(ch, &ch); + if (*ch == timeSep) { + ++ch; + if ((timeSep == ',') || (timeSep == '.')) { + //We can't do fractional minutes when '.' is the segment separator. + //Only allow whole minutes and whole seconds. + minute = read_segment_2digits(ch, &ch); + if (*ch == timeSep) { + ++ch; + second = read_segment_2digits(ch, &ch); + } + } else { + //Allow a fractional minute. + //If we don't get a fraction, look for a seconds segment. + //Otherwise, the fraction of a minute is the seconds. + minute = read_double(ch, &ch); + second = modf(minute, &minute); + if (second > DBL_EPSILON) + second *= 60.0; //Convert fraction (e.g. .5) into seconds (e.g. 30). + else if (*ch == timeSep) { + ++ch; + second = read_double(ch, &ch); + } + } + } + + if (!strict) { + if (isspace(*ch)) ++ch; + } + + switch(*ch) { + case 'Z': + timeZone = [NSTimeZone timeZoneWithAbbreviation:@"UTC"]; + break; + + case '+': + case '-':; + BOOL negative = (*ch == '-'); + if (isdigit(*++ch)) { + //Read hour offset. + segment = *ch - '0'; + if (isdigit(*++ch)) { + segment *= 10U; + segment += *(ch++) - '0'; + } + tz_hour = (NSInteger)segment; + if (negative) tz_hour = -tz_hour; + + //Optional separator. + if (*ch == timeSep) ++ch; + + if (isdigit(*ch)) { + //Read minute offset. + segment = *ch - '0'; + if (isdigit(*++ch)) { + segment *= 10U; + segment += *ch - '0'; + } + tz_minute = segment; + if (negative) tz_minute = -tz_minute; + } + + NSTimeInterval timeZoneOffset = (tz_hour * 3600) + (tz_minute * 60); + NSNumber *offsetNum = [NSNumber numberWithDouble:timeZoneOffset]; + timeZone = [timeZonesByOffset objectForKey:offsetNum]; + if (!timeZone) { + timeZone = [NSTimeZone timeZoneForSecondsFromGMT:timeZoneOffset]; + if (timeZone) + [timeZonesByOffset setObject:timeZone forKey:offsetNum]; + } + } + } + } + } + + if (isValidDate) { + components.year = year; + components.day = day; + components.hour = hour; + components.minute = (NSInteger)minute; + components.second = (NSInteger)second; + + switch(dateSpecification) { + case monthAndDate: + components.month = month_or_week; + break; + + case week:; + //Adapted from . + //This works by converting the week date into an ordinal date, then letting the next case handle it. + NSUInteger prevYear = year - 1U; + NSUInteger YY = prevYear % 100U; + NSUInteger C = prevYear - YY; + NSUInteger G = YY + YY / 4U; + NSUInteger isLeapYear = (((C / 100U) % 4U) * 5U); + NSUInteger Jan1Weekday = (isLeapYear + G) % 7U; + enum { monday, tuesday, wednesday, thursday/*, friday, saturday, sunday*/ }; + components.day = ((8U - Jan1Weekday) + (7U * (Jan1Weekday > thursday))) + (day - 1U) + (7U * (month_or_week - 2)); + + case dateOnly: //An "ordinal date". + break; + } + } + } //if (!(strict && isdigit(ch[0]))) + + if (outRange) { + if (isValidDate) + range.length = ch - start_of_date; + else + range.location = NSNotFound; + + *outRange = range; + } + if (outTimeZone) { + *outTimeZone = timeZone; + } + + return isValidDate ? components : nil; +} + +- (NSDate *)dateFromString:(NSString *)string +{ + return [self dateFromString:string timeZone:NULL]; +} + +- (NSDate *)dateFromString:(NSString *)string timeZone:(out NSTimeZone **)outTimeZone +{ + return [self dateFromString:string timeZone:outTimeZone range:NULL]; +} + +- (NSDate *)dateFromString:(NSString *)string timeZone:(out NSTimeZone **)outTimeZone range:(out NSRange *)outRange { + NSTimeZone *timeZone = nil; + NSDateComponents *components = [self dateComponentsFromString:string timeZone:&timeZone range:outRange]; + if (! components) return nil; + if (outTimeZone) + *outTimeZone = timeZone; + self.parsingCalendar.timeZone = timeZone ?: self.timeZone; + return [self.parsingCalendar dateFromComponents:components]; +} + +- (BOOL)getObjectValue:(id *)outValue forString:(NSString *)string errorDescription:(NSString **)error +{ + NSDate *date = [self dateFromString:string]; + if (outValue) + *outValue = date; + return (date != nil); +} + +#pragma mark Unparsing + +- (NSString *) replaceColonsInString:(NSString *)timeFormat withTimeSeparator:(unichar)timeSep +{ + if (timeSep != ':') { + NSMutableString *timeFormatMutable = [timeFormat mutableCopy]; + [timeFormatMutable replaceOccurrencesOfString:@":" + withString:[NSString stringWithCharacters:&timeSep length:1U] + options:NSBackwardsSearch | NSLiteralSearch + range:(NSRange){ 0UL, [timeFormat length] }]; + timeFormat = timeFormatMutable; + } + return timeFormat; +} + +- (NSString *)stringFromDate:(NSDate *)date +{ + switch (self.format) { + case RKISO8601DateFormatCalendar: + return [self stringFromDate:date formatString:RK_ISOCALENDAR_DATE_FORMAT]; + case RKISO8601DateFormatWeek: + return [self weekDateStringForDate:date timeZone:self.timeZone]; + case RKISO8601DateFormatOrdinal: + return [self stringFromDate:date formatString:RK_ISOORDINAL_DATE_FORMAT]; + default: + [NSException raise:NSInternalInconsistencyException format:@"self.format was %ld, not calendar (%d), week (%d), or ordinal (%d)", (unsigned long) self.format, RKISO8601DateFormatCalendar, RKISO8601DateFormatWeek, RKISO8601DateFormatOrdinal]; + return nil; + } +} + +- (NSString *)stringFromDate:(NSDate *)date formatString:(NSString *)dateFormat +{ + if (self.includeTime) dateFormat = [dateFormat stringByAppendingFormat:@"'T'%@", [self replaceColonsInString:RK_ISOTIME_FORMAT withTimeSeparator:self.timeSeparator]]; + + if (! [dateFormat isEqualToString:self.lastUsedFormatString]) { + self.unparsingFormatter = nil; + self.lastUsedFormatString = dateFormat; + } + + if (!self.unparsingFormatter) { + self.unparsingFormatter = [[NSDateFormatter alloc] init]; + self.unparsingFormatter.formatterBehavior = NSDateFormatterBehavior10_4; + self.unparsingFormatter.dateFormat = dateFormat; + self.unparsingFormatter.calendar = self.unparsingCalendar; + self.unparsingFormatter.timeZone = self.timeZone; + self.unparsingFormatter.locale = self.locale; + } + + NSString *str = [self.unparsingFormatter stringForObjectValue:date]; + if (self.includeTime) { + NSInteger offset = [self.timeZone secondsFromGMT]; + offset /= 60; //bring down to minutes + if (offset == 0) + str = [str stringByAppendingString:RK_ISOTIMEZONE_UTC_FORMAT]; + else + str = [str stringByAppendingFormat:RK_ISOTIMEZONE_OFFSET_FORMAT, (long) (offset / 60), (long) (offset % 60)]; + } + + return str; +} + +- (NSString *)stringForObjectValue:(id)value +{ + NSParameterAssert([value isKindOfClass:[NSDate class]]); + return [self stringFromDate:(NSDate *)value]; +} + +/*Adapted from: + * Algorithm for Converting Gregorian Dates to ISO 8601 Week Date + * Rick McCarty, 1999 + * http://personal.ecu.edu/mccartyr/ISOwdALG.txt + */ +- (NSString *)weekDateStringForDate:(NSDate *)date +{ + self.unparsingCalendar.timeZone = self.timeZone; + self.unparsingCalendar.locale = self.locale; + NSDateComponents *components = [self.unparsingCalendar components:RK_CALENDAR_UNIT_YEAR | RK_CALENDAR_UNIT_WEEKDAY | RK_CALENDAR_UNIT_DAY fromDate:date]; + + //Determine the ordinal date. + NSDateComponents *startOfYearComponents = [self.unparsingCalendar components:RK_CALENDAR_UNIT_YEAR fromDate:date]; + startOfYearComponents.month = 1; + startOfYearComponents.day = 1; + NSDateComponents *ordinalComponents = [self.unparsingCalendar components:RK_CALENDAR_UNIT_DAY fromDate:[self.unparsingCalendar dateFromComponents:startOfYearComponents] toDate:date options:0]; + ordinalComponents.day += 1; + + enum { + monday, tuesday, wednesday, thursday, friday, saturday, sunday + }; + enum { + january = 1, february, march, + april, may, june, + july, august, september, + october, november, december + }; + + NSInteger year = components.year; + NSInteger week = 0; + //The old unparser added 6 to [calendarDate dayOfWeek], which was zero-based; components.weekday is one-based, so we now add only 5. + NSInteger dayOfWeek = (components.weekday + 5) % 7; + NSInteger dayOfYear = ordinalComponents.day; + + NSInteger prevYear = year - 1; + + BOOL yearIsLeapYear = is_leap_year(year); + BOOL prevYearIsLeapYear = is_leap_year(prevYear); + + NSInteger YY = prevYear % 100; + NSInteger C = prevYear - YY; + NSInteger G = YY + YY / 4; + NSInteger Jan1Weekday = (((((C / 100) % 4) * 5) + G) % 7); + + NSInteger weekday = ((dayOfYear + Jan1Weekday) - 1) % 7; + + if ((dayOfYear <= (7 - Jan1Weekday)) && (Jan1Weekday > thursday)) { + week = 52 + ((Jan1Weekday == friday) || ((Jan1Weekday == saturday) && prevYearIsLeapYear)); + --year; + } else { + NSInteger lengthOfYear = 365 + yearIsLeapYear; + if ((lengthOfYear - dayOfYear) < (thursday - weekday)) { + ++year; + week = 1; + } else { + NSInteger J = dayOfYear + (sunday - weekday) + Jan1Weekday; + week = J / 7 - (Jan1Weekday > thursday); + } + } + + NSString *timeString; + if (self.includeTime) { + NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; + unichar timeSep = self.timeSeparator; + if (!timeSep) timeSep = RKISO8601DefaultTimeSeparatorCharacter; + formatter.dateFormat = [self replaceColonsInString:RK_ISOTIME_WITH_TIMEZONE_FORMAT withTimeSeparator:timeSep]; + + timeString = [formatter stringForObjectValue:date]; + } else + timeString = @""; + + return [NSString stringWithFormat:@"%lu-W%02lu-%02lu%@", (unsigned long)year, (unsigned long)week, ((unsigned long)dayOfWeek) + 1U, timeString]; +} + +@end + +static NSUInteger read_segment(const unsigned char *str, const unsigned char **next, NSUInteger *out_num_digits) { + NSUInteger num_digits = 0U; + NSUInteger value = 0U; + + while(isdigit(*str)) { + value *= 10U; + value += *str - '0'; + ++num_digits; + ++str; + } + + if (next) *next = str; + if (out_num_digits) *out_num_digits = num_digits; + + return value; +} +static NSUInteger read_segment_4digits(const unsigned char *str, const unsigned char **next, NSUInteger *out_num_digits) { + NSUInteger num_digits = 0U; + NSUInteger value = 0U; + + if (isdigit(*str)) { + value += *(str++) - '0'; + ++num_digits; + } + + if (isdigit(*str)) { + value *= 10U; + value += *(str++) - '0'; + ++num_digits; + } + + if (isdigit(*str)) { + value *= 10U; + value += *(str++) - '0'; + ++num_digits; + } + + if (isdigit(*str)) { + value *= 10U; + value += *(str++) - '0'; + ++num_digits; + } + + if (next) *next = str; + if (out_num_digits) *out_num_digits = num_digits; + + return value; +} +static NSUInteger read_segment_2digits(const unsigned char *str, const unsigned char **next) { + NSUInteger value = 0U; + + if (isdigit(*str)) + value += *str - '0'; + + if (isdigit(*++str)) { + value *= 10U; + value += *(str++) - '0'; + } + + if (next) *next = str; + + return value; +} + +//strtod doesn't support ',' as a separator. This does. +static double read_double(const unsigned char *str, const unsigned char **next) { + double value = 0.0; + + if (str) { + NSUInteger int_value = 0; + + while(isdigit(*str)) { + int_value *= 10U; + int_value += (*(str++) - '0'); + } + value = int_value; + + if (((*str == ',') || (*str == '.'))) { + ++str; + + register double multiplier, multiplier_multiplier; + multiplier = multiplier_multiplier = 0.1; + + while(isdigit(*str)) { + value += (*(str++) - '0') * multiplier; + multiplier *= multiplier_multiplier; + } + } + } + + if (next) *next = str; + + return value; +} + +static BOOL is_leap_year(NSUInteger year) { + return \ + ((year % 4U) == 0U) + && (((year % 100U) != 0U) + || ((year % 400U) == 0U)); +} diff --git a/Pods/ISO8601DateFormatterValueTransformer/LICENSE b/Pods/ISO8601DateFormatterValueTransformer/LICENSE new file mode 100644 index 0000000..37ec93a --- /dev/null +++ b/Pods/ISO8601DateFormatterValueTransformer/LICENSE @@ -0,0 +1,191 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright +owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, "control" means (i) the power, direct or +indirect, to cause the direction or management of such entity, whether by +contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising +permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including +but not limited to software source code, documentation source, and configuration +files. + +"Object" form shall mean any form resulting from mechanical transformation or +translation of a Source form, including but not limited to compiled object code, +generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made +available under the License, as indicated by a copyright notice that is included +in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that +is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative Works +shall not include works that remain separable from, or merely link (or bind by +name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version +of the Work and any modifications or additions to that Work or Derivative Works +thereof, that is intentionally submitted to Licensor for inclusion in the Work +by the copyright owner or by an individual or Legal Entity authorized to submit +on behalf of the copyright owner. For the purposes of this definition, +"submitted" means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and +issue tracking systems that are managed by, or on behalf of, the Licensor for +the purpose of discussing and improving the Work, but excluding communication +that is conspicuously marked or otherwise designated in writing by the copyright +owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the Work and such +Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where +such license applies only to those patent claims licensable by such Contributor +that are necessarily infringed by their Contribution(s) alone or by combination +of their Contribution(s) with the Work to which such Contribution(s) was +submitted. If You institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work or a +Contribution incorporated within the Work constitutes direct or contributory +patent infringement, then any patent licenses granted to You under this License +for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof +in any medium, with or without modifications, and in Source or Object form, +provided that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of +this License; and +You must cause any modified files to carry prominent notices stating that You +changed the files; and +You must retain, in the Source form of any Derivative Works that You distribute, +all copyright, patent, trademark, and attribution notices from the Source form +of the Work, excluding those notices that do not pertain to any part of the +Derivative Works; and +If the Work includes a "NOTICE" text file as part of its distribution, then any +Derivative Works that You distribute must include a readable copy of the +attribution notices contained within such NOTICE file, excluding those notices +that do not pertain to any part of the Derivative Works, in at least one of the +following places: within a NOTICE text file distributed as part of the +Derivative Works; within the Source form or documentation, if provided along +with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents of +the NOTICE file are for informational purposes only and do not modify the +License. You may add Your own attribution notices within Derivative Works that +You distribute, alongside or as an addendum to the NOTICE text from the Work, +provided that such additional attribution notices cannot be construed as +modifying the License. +You may add Your own copyright statement to Your modifications and may provide +additional or different license terms and conditions for use, reproduction, or +distribution of Your modifications, or for any such Derivative Works as a whole, +provided Your use, reproduction, and distribution of the Work otherwise complies +with the conditions stated in this License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted +for inclusion in the Work by You to the Licensor shall be under the terms and +conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of +any separate license agreement you may have executed with Licensor regarding +such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides the +Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, +including, without limitation, any warranties or conditions of TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are +solely responsible for determining the appropriateness of using or +redistributing the Work and assume any risks associated with Your exercise of +permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), +contract, or otherwise, unless required by applicable law (such as deliberate +and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, incidental, +or consequential damages of any character arising as a result of this License or +out of the use or inability to use the Work (including but not limited to +damages for loss of goodwill, work stoppage, computer failure or malfunction, or +any and all other commercial damages or losses), even if such Contributor has +been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to +offer, and charge a fee for, acceptance of support, warranty, indemnity, or +other liability obligations and/or rights consistent with this License. However, +in accepting such obligations, You may act only on Your own behalf and on Your +sole responsibility, not on behalf of any other Contributor, and only if You +agree to indemnify, defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason of your +accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work + +To apply the Apache License to your work, attach the following boilerplate +notice, with the fields enclosed by brackets "[]" replaced with your own +identifying information. (Don't include the brackets!) The text should be +enclosed in the appropriate comment syntax for the file format. We also +recommend that a file or class name and description of purpose be included on +the same "printed page" as the copyright notice for easier identification within +third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Pods/ISO8601DateFormatterValueTransformer/README.md b/Pods/ISO8601DateFormatterValueTransformer/README.md new file mode 100644 index 0000000..c08cf6d --- /dev/null +++ b/Pods/ISO8601DateFormatterValueTransformer/README.md @@ -0,0 +1,51 @@ +ISO8601DateFormatterValueTransformer +==================================== + +A small Objective-C library that integrates Peter Hosey's [ISO8601DateFormatter](https://github.com/boredzo/iso-8601-date-formatter) +with [RKValueTransformers](https://github.com/RestKit/RKValueTransformers). + +The implementation is done by adding `RKValueTransforming` conformance to the `ISO8601DateFormatter` via a category. + +## Examples + +### Usage + +Basic usage is identical to all other `RKValueTransforming` classes. + +```objc +#import "ISO8601DateValueTransformer.h" + +RKISO8601DateFormatter *dateFormatter = [RKISO8601DateFormatter defaultISO8601DateFormatter]; + +// Transforming NSDate -> String +NSString *dateString = nil; +NSError *error = nil; +BOOL success = [dateFormatter transformValue:[NSDate date] toValue:&dateString ofClass:[NSDate class] error:&error]; + +// Transforming NSString -> NSDate +NSDate *date = nil; +success = [dateFormatter transformValue:@"2013-09-12T07:24:56-04:00" toValue:&dateString ofClass:[NSDate class] error:&error]; +``` + +### Configuration as Default Date Transformer + +Adding the date formatter to the default value transformer at position 0 ensures that it is used ahead of all other `NSString` <-> `NSDate` value transformers. + +```objc +#import "ISO8601DateValueTransformer.h" + +RKISO8601DateFormatter *dateFormatter = [RKISO8601DateFormatter defaultISO8601DateFormatter]; +[[RKValueTransformer defaultValueTransformer] insertValueTransformer:dateFormatter atIndex:0]; +``` + +## Credits + +Blake Watters + +- http://github.com/blakewatters +- http://twitter.com/blakewatters +- blakewatters@gmail.com + +## License + +ISO8601DateFormatterValueTransformer is available under the Apache 2 License. See the LICENSE file for more info. diff --git a/Pods/Manifest.lock b/Pods/Manifest.lock new file mode 100644 index 0000000..709a18b --- /dev/null +++ b/Pods/Manifest.lock @@ -0,0 +1,42 @@ +PODS: + - AFNetworking (1.3.4) + - GoogleMaps (1.10.3) + - ISO8601DateFormatterValueTransformer (0.6.1): + - RKValueTransformers (~> 1.1.0) + - RestKit (0.25.0): + - RestKit/Core (= 0.25.0) + - RestKit/Core (0.25.0): + - RestKit/CoreData + - RestKit/Network + - RestKit/ObjectMapping + - RestKit/CoreData (0.25.0): + - RestKit/ObjectMapping + - RestKit/Network (0.25.0): + - AFNetworking (~> 1.3.0) + - RestKit/ObjectMapping + - RestKit/Support + - SOCKit + - RestKit/ObjectMapping (0.25.0): + - ISO8601DateFormatterValueTransformer (~> 0.6.1) + - RestKit/Support + - RKValueTransformers (~> 1.1.0) + - RestKit/Support (0.25.0): + - TransitionKit (~> 2.1.0) + - RKValueTransformers (1.1.2) + - SOCKit (1.1) + - TransitionKit (2.1.1) + +DEPENDENCIES: + - GoogleMaps (~> 1.10) + - RestKit (~> 0.25) + +SPEC CHECKSUMS: + AFNetworking: cf8e418e16f0c9c7e5c3150d019a3c679d015018 + GoogleMaps: 945e4ac3b74bcca3ddada51df256eb7beddb474d + ISO8601DateFormatterValueTransformer: 52da467d6ec899d6aedda8e48280ac92e8ee97e6 + RestKit: a4fcaf3d4bb2c204679856a46d596160bf208095 + RKValueTransformers: 66ac5e4f077fdbe3496e792d89eeff4c3eb67701 + SOCKit: c7376ac262bea9115b8f749358f762522a47d392 + TransitionKit: 3a14b6acc7cf2d1dd3e454e24dbad1cfab9a1ef1 + +COCOAPODS: 0.38.2 diff --git a/Pods/Pods.xcodeproj/project.pbxproj b/Pods/Pods.xcodeproj/project.pbxproj new file mode 100644 index 0000000..0228b6d --- /dev/null +++ b/Pods/Pods.xcodeproj/project.pbxproj @@ -0,0 +1,1861 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 00159301B6C98C7E2CEF4BEA9E1B45A8 /* RKConnectionDescription.m in Sources */ = {isa = PBXBuildFile; fileRef = 355D30AA75F7200E1391EE2F9850AAFD /* RKConnectionDescription.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 003922F3F435C70F3059B35631F20291 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA1E66EECB2CCEA42260109F42EBA268 /* SystemConfiguration.framework */; }; + 02FC94B48589009C42B710CF70B8D5DF /* RKLumberjackLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 1CE577C871C6339B325216DAA1E9C380 /* RKLumberjackLogger.h */; }; + 05AE8098E6A68548AE55F558538DA530 /* RKManagedObjectMappingOperationDataSource.h in Headers */ = {isa = PBXBuildFile; fileRef = 5F2C28CF81EE920F924A4832B385A2ED /* RKManagedObjectMappingOperationDataSource.h */; }; + 06418D23A05B289562DC2DD4D7B81478 /* RKManagedObjectRequestOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 14D546CDCEF1964FA21938D1D24E0A61 /* RKManagedObjectRequestOperation.h */; }; + 06FBDBD1B1926434DEB60A12D8D94788 /* RKValueTransformers.m in Sources */ = {isa = PBXBuildFile; fileRef = DB7BEEC0D36BBE2BA710A0AEB72C6340 /* RKValueTransformers.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 07074DCE20E9D5E18C47C82C7BE85512 /* AFHTTPRequestOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 37F81F4EA220D0B72285D504A5F4F6AF /* AFHTTPRequestOperation.h */; }; + 0722E90FFB0E0659D82D8E560CA2D2F1 /* TKStateMachine.m in Sources */ = {isa = PBXBuildFile; fileRef = 4391678EE65327EC09710A2246AE3738 /* TKStateMachine.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 09A4819C981D051CF3CF4D383AF60C19 /* RKLumberjackLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = FBCDACF4953305A48F143D830F6A8B33 /* RKLumberjackLogger.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 09C078638B2314EDC932C7F8F610E764 /* NSManagedObject+RKAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = AB2F08445612D3FEDB688B73B2B89289 /* NSManagedObject+RKAdditions.h */; }; + 0BBA7C712421887DDD5B27A1E1CA5086 /* RKEntityByAttributeCache.m in Sources */ = {isa = PBXBuildFile; fileRef = B12031C3E62BD36C971135BE9E4A8093 /* RKEntityByAttributeCache.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 0C5F579A13AD494E6D548F0C0953EAD9 /* AFNetworkActivityIndicatorManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 82CAEF9FA55FE7D5E36A20E10D584C1C /* AFNetworkActivityIndicatorManager.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 0EF36DBD862CFA8CD361D4A78233C472 /* RKRoute.h in Headers */ = {isa = PBXBuildFile; fileRef = C87B4270FD59E85DA2A1FB79F03BCED7 /* RKRoute.h */; }; + 11D168CB2159ED3CBF8C46EBFFAB9375 /* RKManagedObjectMappingOperationDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 4EEE3DF4039896AC75D7A94A0F772E64 /* RKManagedObjectMappingOperationDataSource.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 13354F84F76DBA512EEC93E1BE523B3B /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A073456F96570555C23C9FC55D278495 /* Security.framework */; }; + 159FBA2393B76374AC530CA087152929 /* AFPropertyListRequestOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = C4453AFB84A3DEAF1C42589840511DC4 /* AFPropertyListRequestOperation.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 16D390EF5962B18B3398279A5794C35A /* RKMapperOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = B855E065D967A0FB50C5E2EA494CC30E /* RKMapperOperation.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 17740E8D1F9A01D5E9D01B5D4A049AAA /* RKDotNetDateFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = 9218BCE40D1CE071C875CD2227624D65 /* RKDotNetDateFormatter.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 186C04D79AC22AE39323DF7CDCB5EAD5 /* RKMapperOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = A5C79D0DA910AC71493B65AD46DBFB51 /* RKMapperOperation.h */; }; + 19D70B83BF8F0332A162228223EA92FB /* RKEntityByAttributeCache.h in Headers */ = {isa = PBXBuildFile; fileRef = DE78C0DAAE0ECFC194E7F021969A990A /* RKEntityByAttributeCache.h */; }; + 19F14817D21FB3495F930C964111B9A4 /* RKMappingOperationDataSource.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D5FBCC9C173CC91E1FCAF4635AD656D /* RKMappingOperationDataSource.h */; }; + 1AAABDEF9A1A58A790D2A024BB2DE56F /* RKFetchRequestManagedObjectCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 26209DEBD0F8891CB1E2A68269B24B3F /* RKFetchRequestManagedObjectCache.h */; }; + 1C6C78E700C93A3F406847A8DE335052 /* lcl_config_logger_RK.h in Headers */ = {isa = PBXBuildFile; fileRef = 2496B383543745B1828664CEF6069019 /* lcl_config_logger_RK.h */; }; + 1FF3660FAF22C06576FC1D0012129E02 /* RKPathMatcher.h in Headers */ = {isa = PBXBuildFile; fileRef = A74E5D8F04AA4E80349CCE11A4EABC2A /* RKPathMatcher.h */; }; + 213FF46BFDA397F7626AF1B49D55956A /* RKMappingOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 1F8A9AA5696F58812E15720C7188EE1C /* RKMappingOperation.h */; }; + 22A54BDE1E03FC728A1B8095A6CAC7A2 /* RKErrorMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = BA457F3A2935EDA97B4CB28C14302B64 /* RKErrorMessage.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 235FB2009F139FF0D6D9732295B6B165 /* RKSerialization.h in Headers */ = {isa = PBXBuildFile; fileRef = 57B7FA85F7FF4BC986930EAF9AEB8AE4 /* RKSerialization.h */; }; + 26915C193CCB7FF7AC7444ACAB49F23B /* RKDictionaryUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D9740419F0E776F1FABB904D5CA004A /* RKDictionaryUtilities.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 2785DDF6BEDB173C21ABB64AE5E6D70A /* RKPaginator.m in Sources */ = {isa = PBXBuildFile; fileRef = EF788416FA16290F6645BCE0435437AE /* RKPaginator.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 28D1EB89FFFEC1A2428C054E6DE77D39 /* RKOperationStateMachine.m in Sources */ = {isa = PBXBuildFile; fileRef = 69254A440F2B5109BFEBBB7F222C4E33 /* RKOperationStateMachine.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 2C7FBD7862DF7ED7977D53138646053B /* RKHTTPRequestOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = B2BADBAB5E57898066A5BF57C7711E8B /* RKHTTPRequestOperation.h */; }; + 2C9C9BEB619088543C81B35B355E573D /* AFJSONRequestOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 8503AAFA23E65CD4CFC1BC142EF0880F /* AFJSONRequestOperation.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 2F1F6FA5BF85956CEC4E228790D1CA2F /* lcl_RK.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A023459CEFDFF7132C0E8E5EA88B24D /* lcl_RK.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 3117F1F1B481FC575970F85E2770EAE2 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2763EF8A157B940CA30BFB421AC0ABA8 /* Foundation.framework */; }; + 387A32E066C413938EE3DF87F73F1495 /* RKObjectUtilities.h in Headers */ = {isa = PBXBuildFile; fileRef = 6775ABB2FDC1D38BB156811370A081BE /* RKObjectUtilities.h */; }; + 3C3C6A6F18D48756F82A928065F9EE95 /* AFImageRequestOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = FE59913ED3A4732BB41A9091E0CE1831 /* AFImageRequestOperation.h */; }; + 3C5A2533640256DFA4741B3BF70CB471 /* RKAttributeMapping.m in Sources */ = {isa = PBXBuildFile; fileRef = 3714579E6A77AF6BA29C2BF928C9B606 /* RKAttributeMapping.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 3CFE326D184C35F88BDE3AF58A47B589 /* RKObjectParameterization.h in Headers */ = {isa = PBXBuildFile; fileRef = DC38339D1F6208C3F3EC097654FB5266 /* RKObjectParameterization.h */; }; + 413589AC9FD0D5E6381069D6D8456B33 /* RKMapping.m in Sources */ = {isa = PBXBuildFile; fileRef = 60A36A6CB5A18DCFF1C8BDEBF3DF48CE /* RKMapping.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 42FE9F2674F4A05270725F0985349D4C /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2763EF8A157B940CA30BFB421AC0ABA8 /* Foundation.framework */; }; + 4311F0AAEBACD972A3BCA0A1F375257D /* Pods-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = AE9B1AB727BB27D6269E9161365EBD5D /* Pods-dummy.m */; }; + 4443DA164C04807EF22B9E2FE3A40CEE /* TKEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = 02B4ADB1ECAC920122E657AE18B10BFE /* TKEvent.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 44EEBB71B919C890EC133515DAADA53E /* SOCKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 96A98B34414903617DDCC4DD35D0ACC8 /* SOCKit.h */; }; + 44FD0F553976021B8ECF5C1822266ABA /* RKHTTPUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 83702DD2C5D49085FC3C98D95063C244 /* RKHTTPUtilities.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 45A721C168090AABDE63D52EED273D7E /* RKFetchRequestManagedObjectCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 68BB64A5DA74B805350B4DDCC2CEC42C /* RKFetchRequestManagedObjectCache.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 471DA3AA75BA868460EF227585BBD852 /* AFHTTPClient.m in Sources */ = {isa = PBXBuildFile; fileRef = A7AA1C9D195A03A7CB6CCC4C59B24D75 /* AFHTTPClient.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 484A53B1B043BE7E8D7C98CE6CE11D6F /* RKHTTPRequestOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = E9BDA006E4FED9FEB5518B6D00A67263 /* RKHTTPRequestOperation.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 48E2BA503D8ECCF77AC0EC3366459A07 /* RKStringTokenizer.h in Headers */ = {isa = PBXBuildFile; fileRef = 825B0623122A3C6D3BDA5F37B8B9FE64 /* RKStringTokenizer.h */; }; + 493D2A390E73C85B5D7D90A40BF2A52B /* RKObjectMapping.m in Sources */ = {isa = PBXBuildFile; fileRef = 444FC2341F629885838C0D9C08592DA2 /* RKObjectMapping.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 4B59AEDB18E741D6254C5BFEACF87FE9 /* RKOperationStateMachine.h in Headers */ = {isa = PBXBuildFile; fileRef = 0EF40613DF53B1FB6902B2CAC50A651E /* RKOperationStateMachine.h */; }; + 4B6DB470CB0437173A8ACF0A346DAC20 /* AFNetworking-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = D359D03F6001570CBB455FAC918986F7 /* AFNetworking-dummy.m */; }; + 4D11949A5ED3449CBBA01F8B379C9977 /* RKCoreData.h in Headers */ = {isa = PBXBuildFile; fileRef = 86BB61D2391D09636581699CCC11BC20 /* RKCoreData.h */; }; + 4DF3134DB56A588569FEC601E6885010 /* RKMacros.h in Headers */ = {isa = PBXBuildFile; fileRef = E7AF3A6C1F3EBBDDC45435DE443FB8D7 /* RKMacros.h */; }; + 510E66C0F3C15C63E813B43B6D299F00 /* UIImageView+AFNetworking.m in Sources */ = {isa = PBXBuildFile; fileRef = FE3330F6814BB0DD40B5BF23DDB44CEA /* UIImageView+AFNetworking.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 511BBAAC3058BA57EDC0A144BC1EC9B1 /* RKObjectRequestOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = ECBC1A0C2A02762F1E83F3050A46FBEF /* RKObjectRequestOperation.h */; }; + 53D8A6C1F5BE588CCD5A070405A17BA8 /* RKURLEncodedSerialization.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DEF5A2506038F276A17FD8EFD4250B5 /* RKURLEncodedSerialization.h */; }; + 55EF216D5857AA144044D9373EC2643B /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2763EF8A157B940CA30BFB421AC0ABA8 /* Foundation.framework */; }; + 5B41FABAD8E3D8448EB80144DE05162A /* RKPropertyInspector.h in Headers */ = {isa = PBXBuildFile; fileRef = 1C2727A5C3ED5938FF430DC0A3D84E14 /* RKPropertyInspector.h */; }; + 5D0EDEA52D1557387DC0F127C0607C8E /* RKObjectMappingOperationDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = C1697E4A1C37410EA218CD801A3D8F96 /* RKObjectMappingOperationDataSource.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 5D57EC90E127CF3481FFEF4BF3169769 /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FBFBD757BF729B37665318B9758927C8 /* MobileCoreServices.framework */; }; + 5E98FDFF26CDAF1425208820335CB061 /* RKConnectionDescription.h in Headers */ = {isa = PBXBuildFile; fileRef = 288DCADD78B9359AC1A27B99DDACC512 /* RKConnectionDescription.h */; }; + 5FE47AF12D37691C922FF07F36E472D9 /* RKObjectParameterization.m in Sources */ = {isa = PBXBuildFile; fileRef = EF8D331ECDED3685C263A77DDC1C1106 /* RKObjectParameterization.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 602B1446FAA28671D5D1338EEEC09C1F /* lcl_config_components_RK.h in Headers */ = {isa = PBXBuildFile; fileRef = 00171B758ECFF00C265F2EA583C95CA4 /* lcl_config_components_RK.h */; }; + 60D6622FFAFF8C593110C093AA5AE054 /* ISO8601DateFormatterValueTransformer.h in Headers */ = {isa = PBXBuildFile; fileRef = 3817F79A2FFAFA957786169D44338961 /* ISO8601DateFormatterValueTransformer.h */; }; + 631C2D635D055B906CDAF4DF48800C54 /* RKObjectRequestOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B93150D00B31A6AA70DB23B61FF989F /* RKObjectRequestOperation.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 64BE1EE97C0B7E4AA6DD31FE41225E5D /* RKManagedObjectCaching.h in Headers */ = {isa = PBXBuildFile; fileRef = 78615091D9077E11CDD208BB528484D0 /* RKManagedObjectCaching.h */; }; + 65396D00CDC745B51EB42B92A9510A12 /* RKResponseDescriptor.h in Headers */ = {isa = PBXBuildFile; fileRef = 2C0ECC4F6DF50C1021A4526C66DAFFA8 /* RKResponseDescriptor.h */; }; + 66468A541A9F0EB06E0FBB97539562E3 /* lcl_config_extensions_RK.h in Headers */ = {isa = PBXBuildFile; fileRef = B6B11130FEB122F4D5A3C9EF4765AAF7 /* lcl_config_extensions_RK.h */; }; + 67A779BC3625EFF978BB358B8BECDD3D /* RKObjectMappingMatcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 075FCDDF36844F6C78BF403DD8A12FE8 /* RKObjectMappingMatcher.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 696C46EE2CFB740888793208E42B25C0 /* RKRouter.h in Headers */ = {isa = PBXBuildFile; fileRef = 09E4F74A52C00EF1C720E047C359B03F /* RKRouter.h */; }; + 6B8655482FEEB3176CC12ED2D76FD5A4 /* RestKit-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = FBD6BCC976E19538049A41A68497F025 /* RestKit-dummy.m */; }; + 6C16B969866DB74F5BA4BB69E70A7CD0 /* RKPropertyMapping.m in Sources */ = {isa = PBXBuildFile; fileRef = 913CE9ED58A6F60DDEA5AA890FF1F48C /* RKPropertyMapping.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 6C98A7F2659D90328BE72A5884878347 /* RKManagedObjectStore.h in Headers */ = {isa = PBXBuildFile; fileRef = 51FB5E1BA147BA2BF2006C014F98C0F4 /* RKManagedObjectStore.h */; }; + 6E7E825054211CBFB06A7F065E772FFE /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA1E66EECB2CCEA42260109F42EBA268 /* SystemConfiguration.framework */; }; + 72BE31A2DBBAF59C41F07D54ACF19682 /* RKMapperOperation_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 1F862DAA8C5D3F9A21B8FDD6DBB5BE92 /* RKMapperOperation_Private.h */; }; + 73FD34365A5B80EC64B0B5A8E99AF46E /* TKState.h in Headers */ = {isa = PBXBuildFile; fileRef = A4F85A759F06DA2C165FC5F9C67479D9 /* TKState.h */; }; + 75C23CBCDF34BCBAD7EBF64991F23EE3 /* RKRelationshipMapping.m in Sources */ = {isa = PBXBuildFile; fileRef = 27FB687584CA64BD1F2AAE24301EE980 /* RKRelationshipMapping.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 77D9A95773F05BD98ECED9F3C2D04F51 /* AFImageRequestOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = A41B62B0D621AA6C11392F766FCD51FE /* AFImageRequestOperation.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 7BE64592FA01CC5C59B9E77C1A22DACB /* RKNSJSONSerialization.m in Sources */ = {isa = PBXBuildFile; fileRef = 96D5B99F66D4E009B90BD61EBF7408AB /* RKNSJSONSerialization.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 7D614D2691101C18B40ED2D26F9B1D01 /* RKEntityMapping.m in Sources */ = {isa = PBXBuildFile; fileRef = BE2DEDDD86B0FA6D80CA5A041B52C16C /* RKEntityMapping.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 804DCE62D40FDE2DCB87C6B561C3CF8E /* Network.h in Headers */ = {isa = PBXBuildFile; fileRef = E8F3DFF4383693E425C06F36BFF9F034 /* Network.h */; }; + 82A9639187AD655DF78D741C32B97F25 /* RKRelationshipConnectionOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = E98F870EB992340D88A021CF973C564D /* RKRelationshipConnectionOperation.h */; }; + 843F7238D7686D3EDF2A512BEB56D348 /* RKEntityMapping.h in Headers */ = {isa = PBXBuildFile; fileRef = F5328AD4D1FFC55D735BE48F5E658C13 /* RKEntityMapping.h */; }; + 84545A853EB47D7A15412CAEF81691FC /* RKDictionaryUtilities.h in Headers */ = {isa = PBXBuildFile; fileRef = 73B51CD9C883E11B8078E0974C555E8C /* RKDictionaryUtilities.h */; }; + 8526C9EF4EE664BFA507C921AFACEF23 /* TransitionKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 8A3CCA72533E35C4376B1E8AECC9627F /* TransitionKit.h */; }; + 8528D500AF6F16347DBB2A9AB5C17684 /* RKPathMatcher.m in Sources */ = {isa = PBXBuildFile; fileRef = B963B3236B5FD7C7902A5D99E7F7E95B /* RKPathMatcher.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 8627F96A7A43B5FC7AD9681E5FE53DD5 /* RKInMemoryManagedObjectCache.h in Headers */ = {isa = PBXBuildFile; fileRef = CD92A31E153551EE24F6972E506E3984 /* RKInMemoryManagedObjectCache.h */; }; + 8CFF8AAB18381D4BB6731F0C88B997E6 /* RKResponseDescriptor.m in Sources */ = {isa = PBXBuildFile; fileRef = BAEBFACE85B965081E04ADDC13F2AB76 /* RKResponseDescriptor.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 8E5D38FD317C57488B159F49FD3A8CCC /* RKPropertyInspector+CoreData.m in Sources */ = {isa = PBXBuildFile; fileRef = DBC84FD9E910C0EA092051869B07A569 /* RKPropertyInspector+CoreData.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 8FE5788EF14F6E44BD11EA5B8C3C1587 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2763EF8A157B940CA30BFB421AC0ABA8 /* Foundation.framework */; }; + 921F52B8F7CAA90D61666CD8529416E6 /* RKEntityCache.m in Sources */ = {isa = PBXBuildFile; fileRef = DF0F7A2381BDDF3CE3B4A6CE3B1DADBE /* RKEntityCache.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 955AF3408EE35750E3097FF257EF1C4C /* RKRequestDescriptor.h in Headers */ = {isa = PBXBuildFile; fileRef = 8B521FF0C82B79C4BA11F04BB245D3AD /* RKRequestDescriptor.h */; }; + 95E280925ADF11A0BA7F705C1885F5DC /* RKObjectManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 421DCDF4B392934B3767CC0EFAC4B66C /* RKObjectManager.h */; }; + 98295AD03AB36FD9257B157FF62B2579 /* ISO8601DateFormatterValueTransformer-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = FC8E48FFBC54C4B5596828D905E3BC9D /* ISO8601DateFormatterValueTransformer-dummy.m */; }; + 99F872BB5976264AD7648F8F8252D8B5 /* TKTransition.h in Headers */ = {isa = PBXBuildFile; fileRef = F0CB4E3EC1ACD76F2309A54B490DF091 /* TKTransition.h */; }; + 9C41DECE303A7A43376A55CEF2FBCE95 /* RKEntityCache.h in Headers */ = {isa = PBXBuildFile; fileRef = E97048C221239B35B2B30FE746BA1B19 /* RKEntityCache.h */; }; + 9C79801284A040CF9286B70FD0E49711 /* ObjectMapping.h in Headers */ = {isa = PBXBuildFile; fileRef = 0033106B5FFABEDBCF4AA601848E6A80 /* ObjectMapping.h */; }; + 9CA67BACED9C9D40AE7B87ED3B1F39D6 /* RKObjectUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B56547657777695ED964437D29CF06F /* RKObjectUtilities.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 9CD9F914F536E8DE8E6155BDC5791E4D /* NSManagedObject+RKAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = D656844F12E1C432C199C2FAC5D3C060 /* NSManagedObject+RKAdditions.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 9D1CFCDA0AD746AEC3349E5EFFF0729B /* AFURLConnectionOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 8A370A0CBD0F14A336B48549716953A2 /* AFURLConnectionOperation.h */; }; + 9F1A9CCF11D95B355DBD688895AFAB0C /* RKErrors.m in Sources */ = {isa = PBXBuildFile; fileRef = 46FB2E21EF84A959B269657382ED17C6 /* RKErrors.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + 9F3446FD81B98C845E0DAFDD62913FDB /* RestKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 2C0BDC65F8FF87BF77753725100E83D1 /* RestKit.h */; }; + A07A8D5FC4840F776938B60C6FB246EC /* RKErrorMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = C2E39A8AA6B454E44B785823DCAF4253 /* RKErrorMessage.h */; }; + A138C9CC8F1734DC526276C176875C94 /* RKManagedObjectStore.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A01AB4B80B7DCCB9F7C5C552E05BB8D /* RKManagedObjectStore.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + A14E1DB45EA2308F962F434472960DF8 /* RKMappingOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = EBEDF339EF5DF85BC77639D611E818B8 /* RKMappingOperation.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + A265586D9672B0A78DA648653B24B0C3 /* RKPropertyInspector+CoreData.h in Headers */ = {isa = PBXBuildFile; fileRef = 1BC614B568932C16177C4FAF9CCEF03C /* RKPropertyInspector+CoreData.h */; }; + A2C5AE290D32BB07ADBC57590BF79B8B /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2763EF8A157B940CA30BFB421AC0ABA8 /* Foundation.framework */; }; + A3325C43A0153A8D78947A8AEA9889E9 /* NSManagedObjectContext+RKAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 6089BF8DFE413DFABE2316758D79A9E0 /* NSManagedObjectContext+RKAdditions.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + A4285902E75A9B36452F261732169903 /* RKMappingErrors.h in Headers */ = {isa = PBXBuildFile; fileRef = 0138C2B05B8104023FA70A92886EF7AA /* RKMappingErrors.h */; }; + A433A73D0FBCFE93C944C162548EA55C /* ISO8601DateFormatterValueTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = E2DD1C139C6511B2ED108234B26B3549 /* ISO8601DateFormatterValueTransformer.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + A553464682FB751898EE249DD887C975 /* RKPropertyMapping.h in Headers */ = {isa = PBXBuildFile; fileRef = 5A96D00C413528D13CFFF3F98BA97ABF /* RKPropertyMapping.h */; }; + A59FDF68B16F36F332C84BCED4B56A9A /* RKMIMETypes.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B62D9AD5CDC11C216E0871A1E30CF16 /* RKMIMETypes.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + A5BE02D3806FDB367A4129949CCC7567 /* AFPropertyListRequestOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 86A7FF814F2BB8CE7941F41F4DB93D47 /* AFPropertyListRequestOperation.h */; }; + A695A94853169B3E07FE3343C48A8E05 /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FE8E6A9A05AB1426D9E86AAC2DDDB14E /* CFNetwork.framework */; }; + A812943B1CC510887FA5A5D029C87A08 /* RKRoute.m in Sources */ = {isa = PBXBuildFile; fileRef = AB33A5CB02849F1DE28836DEE20E225D /* RKRoute.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + A83AD78FED2B02AE79871685A11FBA76 /* RKManagedObjectRequestOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = B19EB35698C23661E2056A801F3CA85E /* RKManagedObjectRequestOperation.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + A8AEF0B683BD5849CD69DDFB593970C6 /* RKMappingResult.h in Headers */ = {isa = PBXBuildFile; fileRef = 3201B0055A4CC8749A6C9573EB16F156 /* RKMappingResult.h */; }; + A8C7AF57E9E8301BBBD2328F099C23A3 /* NSManagedObjectContext+RKAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = B594C1A9FEE6DB22895B832E9F44EA18 /* NSManagedObjectContext+RKAdditions.h */; }; + A93C5853F5BE181FB80CDF8C1189AD18 /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FBFBD757BF729B37665318B9758927C8 /* MobileCoreServices.framework */; }; + AAE115E50155948641D97F4C4782327B /* TKEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 40C40C0517D7C210D4A32215DEB225C1 /* TKEvent.h */; }; + AB2FFBD48FA0942C55246A46CED2C9E9 /* RKISO8601DateFormatter.h in Headers */ = {isa = PBXBuildFile; fileRef = 8154C55352F65270356E82260D9D0BC6 /* RKISO8601DateFormatter.h */; }; + AC66A0C3B2CD40FAF63B969C22002667 /* RKResponseMapperOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 41B98447BAE742CDDF19066AAC6AAC37 /* RKResponseMapperOperation.h */; }; + AE61F69B4265A18A01C3E0E7333F8DA4 /* RKPropertyInspector.m in Sources */ = {isa = PBXBuildFile; fileRef = 5FDC132C654FF745DD4CFC455B189BD4 /* RKPropertyInspector.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + AED7DD46159F1525CBAED2B765B6FBB2 /* SOCKit-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 4FE09EB1BAFD6593655A66644AD9F2C0 /* SOCKit-dummy.m */; }; + AEF152DEB9D69B47F9BBF7E427E90A0E /* TKStateMachine.h in Headers */ = {isa = PBXBuildFile; fileRef = C7A3C431941CA5458B46FDA87ADD17E9 /* TKStateMachine.h */; }; + AF5121CEE8BC0D2D902659375844C937 /* RKObjectMappingMatcher.h in Headers */ = {isa = PBXBuildFile; fileRef = 20D708DAD41809C2158DF41AED4C2D4E /* RKObjectMappingMatcher.h */; }; + AFDA7900BE8CA77BB17C961E3BC02958 /* AFHTTPClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 67B224EC11AFE6EC20CAC138BAAB212C /* AFHTTPClient.h */; }; + B0C6E840F6C838687FD759E421F8DDE8 /* RKURLEncodedSerialization.m in Sources */ = {isa = PBXBuildFile; fileRef = A08639AFDB6619D2C8C75E2CA6E6FABA /* RKURLEncodedSerialization.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + B0F14B6E203AC5C434348441B36A2722 /* RKMIMETypes.h in Headers */ = {isa = PBXBuildFile; fileRef = 801774778ACB915E071F725B50208B91 /* RKMIMETypes.h */; }; + B22432E8FC8424E1514FA26CD8DF29A8 /* RKValueTransformers.h in Headers */ = {isa = PBXBuildFile; fileRef = 330A6D2DE7F31FDDC4FDF2BB3D2FB16F /* RKValueTransformers.h */; }; + B28FCECFA61DD7C62C8D719CB6F0A4C0 /* RKResponseMapperOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B111C75C47C01AD77014B63358CFC32 /* RKResponseMapperOperation.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + B384C39C1181D85CCFA031C87CC35DA8 /* AFXMLRequestOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = DA9B5ECC134F1E032125D1094DE52029 /* AFXMLRequestOperation.h */; }; + B3A2CFAB459DD270F6C9ED1ED3116C3A /* RKDynamicMapping.h in Headers */ = {isa = PBXBuildFile; fileRef = C19660B39C046CB326B68607FB0228FC /* RKDynamicMapping.h */; }; + B3A6803F1565A9C7CE4DE075228F8617 /* RKObjectRequestOperationSubclass.h in Headers */ = {isa = PBXBuildFile; fileRef = 177CA429DCED072B6E1AE95498045736 /* RKObjectRequestOperationSubclass.h */; }; + B51FF19CCD1732C53786D1FA1D7A414F /* RKPathUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 9502AACFA962A1F7AD805C8D0F0714EA /* RKPathUtilities.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + B7D1E227311A8524D25969B0E3A3C7ED /* RKRequestDescriptor.m in Sources */ = {isa = PBXBuildFile; fileRef = F5CE8BC88F72A12FE1283DBF0A070E89 /* RKRequestDescriptor.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + B8291EBC0CA538454602E54BDA92A1B7 /* TransitionKit-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 15854EBB45118A734AE77C8EFB408F10 /* TransitionKit-dummy.m */; }; + B97F7A2BA951D87E943FFE51C6D1721D /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2763EF8A157B940CA30BFB421AC0ABA8 /* Foundation.framework */; }; + BA8C9A927C8E7BAD715C1EEF7ACDA79B /* RKObjectMapping.h in Headers */ = {isa = PBXBuildFile; fileRef = 10E7656293309EA130C59D062696C0E8 /* RKObjectMapping.h */; }; + BF6090929BE8D0BDFE25DC50BB59C698 /* RKRelationshipConnectionOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 815E808EAA76782C0E2910798238C1CE /* RKRelationshipConnectionOperation.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + C2406F161CC120D07B885E6D8D930DB3 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2763EF8A157B940CA30BFB421AC0ABA8 /* Foundation.framework */; }; + C2A46EF6A663BC8C3ACFEE6CBE3FAFEB /* RKRouter.m in Sources */ = {isa = PBXBuildFile; fileRef = 5370AF9DFC5C717414F78FBE75FB86A3 /* RKRouter.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + C35137BF1721ED975122EFB940442BE4 /* RKDynamicMapping.m in Sources */ = {isa = PBXBuildFile; fileRef = 9F85354D369A63FDA2DD23B9DECB7FEF /* RKDynamicMapping.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + C375D977229721851615EB9E33421C78 /* AFURLConnectionOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = C70C9BCC7A26C68B1B5D686E6E44B247 /* AFURLConnectionOperation.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + C586ECC71F71C909A4BF55ADEBAA0B86 /* RKMappingResult.m in Sources */ = {isa = PBXBuildFile; fileRef = 71F6AABF844EEFEB27E227BB0E2023EF /* RKMappingResult.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + C731F1A9652EB02201D53C378E3AECD9 /* lcl_RK.h in Headers */ = {isa = PBXBuildFile; fileRef = 89771AEAB0B05F90650D107E81B24E15 /* lcl_RK.h */; }; + CBC217725771FAA918C235535861F443 /* AFNetworkActivityIndicatorManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 943190F187AC5F8FB83B38BE9196CE1B /* AFNetworkActivityIndicatorManager.h */; }; + CC8EE054A94737C7B6463B66AB5D7F35 /* AFJSONRequestOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 1CF18DCA5EB135C7FB73BCD5A881765B /* AFJSONRequestOperation.h */; }; + CCAF5CC514337B555C6902351DF5FA77 /* RKHTTPUtilities.h in Headers */ = {isa = PBXBuildFile; fileRef = ACB1E33D558E9F09939C382A52C6BF1F /* RKHTTPUtilities.h */; }; + CCEEC74BF5A6249F43B8FD40FAA4AC54 /* AFNetworking.h in Headers */ = {isa = PBXBuildFile; fileRef = EE78A9B6E3722476ED12EDAAF4C9C2E8 /* AFNetworking.h */; }; + D25C7E2A0C55DA3A31BF7E091A1F8E2F /* CoreData.h in Headers */ = {isa = PBXBuildFile; fileRef = FC74CBE84F5FC2A1D0685071DB3F820E /* CoreData.h */; }; + D28C93C0AB9A00F114622E3A574AF13E /* RKDotNetDateFormatter.h in Headers */ = {isa = PBXBuildFile; fileRef = 591F047DDB62DFE9714DB1BD18837A46 /* RKDotNetDateFormatter.h */; }; + D2CC9690359AFF7318391ACDDAC1C48A /* RKRouteSet.h in Headers */ = {isa = PBXBuildFile; fileRef = 20DA68ADE311D013F09FE151A3792BBA /* RKRouteSet.h */; }; + D593064CDF2BF18F89534B515B6EF07E /* RKManagedObjectImporter.m in Sources */ = {isa = PBXBuildFile; fileRef = 3E8A0031D6B5F5BC3372D44FC206C3DD /* RKManagedObjectImporter.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + D6C012BA03CA2D817494AC42792C4C0D /* CoreData.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E65C0BB8745BB49525AEBAFE8CBA3FC9 /* CoreData.framework */; }; + D7806799BEF42E3AF9F018EB11A24AC6 /* RKManagedObjectImporter.h in Headers */ = {isa = PBXBuildFile; fileRef = 36A53F844115F0FCFBC089F15BB2469C /* RKManagedObjectImporter.h */; }; + D9CF2FCF96A7E4AC565DAD67A8A8E0BE /* RKRouteSet.m in Sources */ = {isa = PBXBuildFile; fileRef = D0ABD79E3710B87422441144957CDE12 /* RKRouteSet.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + DC86E3F27825FE1DC63AD5036D9D8975 /* RKMIMETypeSerialization.m in Sources */ = {isa = PBXBuildFile; fileRef = 3A52401BB23052568B1A947BBEDB306E /* RKMIMETypeSerialization.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + DD4C9BA231F24DF9A87997EBCB14A8AC /* RKPathUtilities.h in Headers */ = {isa = PBXBuildFile; fileRef = 74C927694DE2F40C7E060C2E5700792D /* RKPathUtilities.h */; }; + DDF4A5DDE3524075CD8B2CD3F500C7B8 /* RKObjectManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 10D586F7993E35ECFE908332BCAD8D7A /* RKObjectManager.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + DE47E4EC28D55D67ACE12C085797C928 /* RKMIMETypeSerialization.h in Headers */ = {isa = PBXBuildFile; fileRef = 76DAA4F1ED26D9A2EE4ED429C4B1C631 /* RKMIMETypeSerialization.h */; }; + DF07D77FAF571E4C4BA7E60AE18C3B7C /* RKLog.h in Headers */ = {isa = PBXBuildFile; fileRef = 97113E4E5D6665DA629C112370C7ADC2 /* RKLog.h */; }; + E0A877FEF013CFE5C85881F1E3B8EEB7 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D8BA0A77AD35E66CCC406CBCC9B63B7B /* CoreGraphics.framework */; }; + E1E7DE5CD1C45C66F68446702EB588BF /* UIImageView+AFNetworking.h in Headers */ = {isa = PBXBuildFile; fileRef = A2602AEF93C48C7D094AC09E341D7EFB /* UIImageView+AFNetworking.h */; }; + E22A1B2C2827AB6E7FEC96DF736CD35F /* RKLog.m in Sources */ = {isa = PBXBuildFile; fileRef = 03D7C131287E9EB129ECA49C0C3BC29D /* RKLog.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + E35137B0D3B508DB7280840288E1EADE /* RKISO8601DateFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = 7A9005F420A97F873CC7908200857388 /* RKISO8601DateFormatter.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + E3765B1D38848D947246248A47761767 /* AFXMLRequestOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 7C4F5C9AE4AE536F4DDFC2AEE57F30F3 /* AFXMLRequestOperation.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + E492215BF50305DBA7E7CD90763D8757 /* Support.h in Headers */ = {isa = PBXBuildFile; fileRef = E19C172D35667648056819B35F7E7107 /* Support.h */; }; + EABAE5228ACD4A5BE6F30A53F80B9C1E /* TKTransition.m in Sources */ = {isa = PBXBuildFile; fileRef = 2A2306F062D21537BCCD17B8E1265AE8 /* TKTransition.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + EB73AF4C9D61D61F7B1BB0F6C573118D /* SOCKit.m in Sources */ = {isa = PBXBuildFile; fileRef = 89622454B6309852AD9687B0820C02B0 /* SOCKit.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + ECFD9B44DF6C09FB22CAE869501E019C /* RKValueTransformers-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = C7EC6F2637B182461F70DECB756AB989 /* RKValueTransformers-dummy.m */; }; + ED4C390C6C06B4305A562B7B6FCCF56B /* RKMapping.h in Headers */ = {isa = PBXBuildFile; fileRef = 3C97F271E7936BA5558DA15DCCEEF5B4 /* RKMapping.h */; }; + EDDC5483CF7756F74426BDA53D7605C8 /* RKErrors.h in Headers */ = {isa = PBXBuildFile; fileRef = 0A4F9CA2983FD37B4A2F2C3FB29F6469 /* RKErrors.h */; }; + EFE3090E2529A4E4ABF8C2ECF0A47669 /* RKRelationshipMapping.h in Headers */ = {isa = PBXBuildFile; fileRef = 9C4F9F2DEE9D79A1FF1CC7A48B5EFE10 /* RKRelationshipMapping.h */; }; + F001896C78D171217E39EF32BA9115CF /* RKAttributeMapping.h in Headers */ = {isa = PBXBuildFile; fileRef = B64181FBC7BDB50DE4A27D6DF07AD1A5 /* RKAttributeMapping.h */; }; + F575760612D781DD6E76347739392D2A /* RKPaginator.h in Headers */ = {isa = PBXBuildFile; fileRef = EBC5BB06AF51F439764DC4F5158ABC64 /* RKPaginator.h */; }; + F70C49E01E12EBB037350F95EA1AA195 /* RKInMemoryManagedObjectCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 3C6363FD012D2047BA5E3D5721AA4283 /* RKInMemoryManagedObjectCache.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + F88CBAF955FEB5A51E24E84A207F8F44 /* RKObjectMappingOperationDataSource.h in Headers */ = {isa = PBXBuildFile; fileRef = E07CF80BF3E1F92CE6D27E5B54838452 /* RKObjectMappingOperationDataSource.h */; }; + F8EBD2043BE81FB6479A46064E538E3E /* AFHTTPRequestOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 69812CA1FFB4AEEF65A7A3092671B5D0 /* AFHTTPRequestOperation.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + FB8ABED36262DF148645FEAAD7C2AB4A /* RKStringTokenizer.m in Sources */ = {isa = PBXBuildFile; fileRef = D786CAF5775AD1EE25298FE83BCDC4FA /* RKStringTokenizer.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + FD2144C4BC84FA87FB99AF5DF4A659D4 /* TKState.m in Sources */ = {isa = PBXBuildFile; fileRef = 9936ED8D363FA6B09EA60941182E9F3B /* TKState.m */; settings = {COMPILER_FLAGS = "-DOS_OBJECT_USE_OBJC=0"; }; }; + FDCABAF695F563402D326C91601BB0A0 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A073456F96570555C23C9FC55D278495 /* Security.framework */; }; + FF31D1A15BFB36959A7E06B5BF7EBD95 /* RKNSJSONSerialization.h in Headers */ = {isa = PBXBuildFile; fileRef = BAE871BE7529E8BBB941E7EA5791C795 /* RKNSJSONSerialization.h */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 4E98C56CA9779ADCB3C61F7A1F1AFF83 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */; + proxyType = 1; + remoteGlobalIDString = ECE37F5BCF4EB1F3EFFB3120C3ACA70E; + remoteInfo = RKValueTransformers; + }; + 55D0DD33832EAFE92A120CC597EAF3B2 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */; + proxyType = 1; + remoteGlobalIDString = C22CB88F290EB94BA5BAC35D7486F902; + remoteInfo = AFNetworking; + }; + 688D88C28B6DCB5E8C32094C2EA431CF /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */; + proxyType = 1; + remoteGlobalIDString = 01ACB00BFF1DE54BD7E0D352C57CE9FB; + remoteInfo = ISO8601DateFormatterValueTransformer; + }; + 73806796ABDE6BBFA1A787DD54BB4254 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */; + proxyType = 1; + remoteGlobalIDString = A2770197345BCE1622568AECE6B8E824; + remoteInfo = SOCKit; + }; + 7B43A77C8F316F3CD803CA70E1AB057D /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */; + proxyType = 1; + remoteGlobalIDString = 158117D77AED03B83733E51D2D22983B; + remoteInfo = TransitionKit; + }; + 80DD835A894C2B3C5172A736DF792F09 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */; + proxyType = 1; + remoteGlobalIDString = ECE37F5BCF4EB1F3EFFB3120C3ACA70E; + remoteInfo = RKValueTransformers; + }; + 8D73036BA3F631512E91F45A23C95546 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */; + proxyType = 1; + remoteGlobalIDString = 68E291FC1F64705132E3A6E596659EB8; + remoteInfo = RestKit; + }; + B02D98F422302D691069C8B16D8E9D9E /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */; + proxyType = 1; + remoteGlobalIDString = C22CB88F290EB94BA5BAC35D7486F902; + remoteInfo = AFNetworking; + }; + CD584120AE4E2B56F0E00BFB2F0F6097 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */; + proxyType = 1; + remoteGlobalIDString = 01ACB00BFF1DE54BD7E0D352C57CE9FB; + remoteInfo = ISO8601DateFormatterValueTransformer; + }; + D0CC65BEE6F2E3790A7B387750C819B3 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */; + proxyType = 1; + remoteGlobalIDString = A2770197345BCE1622568AECE6B8E824; + remoteInfo = SOCKit; + }; + E35A79A65CE187002FBE64125A9ED690 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */; + proxyType = 1; + remoteGlobalIDString = ECE37F5BCF4EB1F3EFFB3120C3ACA70E; + remoteInfo = RKValueTransformers; + }; + F95EB63EB8212CE724F4F1108117A90D /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D41D8CD98F00B204E9800998ECF8427E /* Project object */; + proxyType = 1; + remoteGlobalIDString = 158117D77AED03B83733E51D2D22983B; + remoteInfo = TransitionKit; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 00171B758ECFF00C265F2EA583C95CA4 /* lcl_config_components_RK.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = lcl_config_components_RK.h; path = Code/Support/lcl_config_components_RK.h; sourceTree = ""; }; + 0033106B5FFABEDBCF4AA601848E6A80 /* ObjectMapping.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = ObjectMapping.h; path = Code/ObjectMapping.h; sourceTree = ""; }; + 0138C2B05B8104023FA70A92886EF7AA /* RKMappingErrors.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKMappingErrors.h; path = Code/ObjectMapping/RKMappingErrors.h; sourceTree = ""; }; + 02B4ADB1ECAC920122E657AE18B10BFE /* TKEvent.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = TKEvent.m; path = Code/TKEvent.m; sourceTree = ""; }; + 03D7C131287E9EB129ECA49C0C3BC29D /* RKLog.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKLog.m; path = Code/Support/RKLog.m; sourceTree = ""; }; + 075FCDDF36844F6C78BF403DD8A12FE8 /* RKObjectMappingMatcher.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKObjectMappingMatcher.m; path = Code/ObjectMapping/RKObjectMappingMatcher.m; sourceTree = ""; }; + 09E4F74A52C00EF1C720E047C359B03F /* RKRouter.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKRouter.h; path = Code/Network/RKRouter.h; sourceTree = ""; }; + 0A4F9CA2983FD37B4A2F2C3FB29F6469 /* RKErrors.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKErrors.h; path = Code/Support/RKErrors.h; sourceTree = ""; }; + 0EF40613DF53B1FB6902B2CAC50A651E /* RKOperationStateMachine.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKOperationStateMachine.h; path = Code/Support/RKOperationStateMachine.h; sourceTree = ""; }; + 10D586F7993E35ECFE908332BCAD8D7A /* RKObjectManager.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKObjectManager.m; path = Code/Network/RKObjectManager.m; sourceTree = ""; }; + 10E7656293309EA130C59D062696C0E8 /* RKObjectMapping.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKObjectMapping.h; path = Code/ObjectMapping/RKObjectMapping.h; sourceTree = ""; }; + 14D546CDCEF1964FA21938D1D24E0A61 /* RKManagedObjectRequestOperation.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKManagedObjectRequestOperation.h; path = Code/Network/RKManagedObjectRequestOperation.h; sourceTree = ""; }; + 15854EBB45118A734AE77C8EFB408F10 /* TransitionKit-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "TransitionKit-dummy.m"; sourceTree = ""; }; + 15A529C27057E4A57D259CBC6E6CE49C /* Pods-acknowledgements.markdown */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = "Pods-acknowledgements.markdown"; sourceTree = ""; }; + 177CA429DCED072B6E1AE95498045736 /* RKObjectRequestOperationSubclass.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKObjectRequestOperationSubclass.h; path = Code/Network/RKObjectRequestOperationSubclass.h; sourceTree = ""; }; + 18AB07DED7A12D04EC0629B6FD0986D6 /* Pods.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = Pods.debug.xcconfig; sourceTree = ""; }; + 1B06BC7B07CE59865D25EF74E0EBA495 /* ISO8601DateFormatterValueTransformer-Private.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "ISO8601DateFormatterValueTransformer-Private.xcconfig"; sourceTree = ""; }; + 1BC614B568932C16177C4FAF9CCEF03C /* RKPropertyInspector+CoreData.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "RKPropertyInspector+CoreData.h"; path = "Code/CoreData/RKPropertyInspector+CoreData.h"; sourceTree = ""; }; + 1C2727A5C3ED5938FF430DC0A3D84E14 /* RKPropertyInspector.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKPropertyInspector.h; path = Code/ObjectMapping/RKPropertyInspector.h; sourceTree = ""; }; + 1CE577C871C6339B325216DAA1E9C380 /* RKLumberjackLogger.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKLumberjackLogger.h; path = Code/Support/RKLumberjackLogger.h; sourceTree = ""; }; + 1CF18DCA5EB135C7FB73BCD5A881765B /* AFJSONRequestOperation.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = AFJSONRequestOperation.h; path = AFNetworking/AFJSONRequestOperation.h; sourceTree = ""; }; + 1F862DAA8C5D3F9A21B8FDD6DBB5BE92 /* RKMapperOperation_Private.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKMapperOperation_Private.h; path = Code/ObjectMapping/RKMapperOperation_Private.h; sourceTree = ""; }; + 1F8A9AA5696F58812E15720C7188EE1C /* RKMappingOperation.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKMappingOperation.h; path = Code/ObjectMapping/RKMappingOperation.h; sourceTree = ""; }; + 20D708DAD41809C2158DF41AED4C2D4E /* RKObjectMappingMatcher.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKObjectMappingMatcher.h; path = Code/ObjectMapping/RKObjectMappingMatcher.h; sourceTree = ""; }; + 20DA68ADE311D013F09FE151A3792BBA /* RKRouteSet.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKRouteSet.h; path = Code/Network/RKRouteSet.h; sourceTree = ""; }; + 2496B383543745B1828664CEF6069019 /* lcl_config_logger_RK.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = lcl_config_logger_RK.h; path = Code/Support/lcl_config_logger_RK.h; sourceTree = ""; }; + 26209DEBD0F8891CB1E2A68269B24B3F /* RKFetchRequestManagedObjectCache.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKFetchRequestManagedObjectCache.h; path = Code/CoreData/RKFetchRequestManagedObjectCache.h; sourceTree = ""; }; + 2763EF8A157B940CA30BFB421AC0ABA8 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS8.3.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; }; + 27FB687584CA64BD1F2AAE24301EE980 /* RKRelationshipMapping.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKRelationshipMapping.m; path = Code/ObjectMapping/RKRelationshipMapping.m; sourceTree = ""; }; + 288DCADD78B9359AC1A27B99DDACC512 /* RKConnectionDescription.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKConnectionDescription.h; path = Code/CoreData/RKConnectionDescription.h; sourceTree = ""; }; + 2A2306F062D21537BCCD17B8E1265AE8 /* TKTransition.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = TKTransition.m; path = Code/TKTransition.m; sourceTree = ""; }; + 2C0BDC65F8FF87BF77753725100E83D1 /* RestKit.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RestKit.h; path = Code/RestKit.h; sourceTree = ""; }; + 2C0ECC4F6DF50C1021A4526C66DAFFA8 /* RKResponseDescriptor.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKResponseDescriptor.h; path = Code/Network/RKResponseDescriptor.h; sourceTree = ""; }; + 2D5FBCC9C173CC91E1FCAF4635AD656D /* RKMappingOperationDataSource.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKMappingOperationDataSource.h; path = Code/ObjectMapping/RKMappingOperationDataSource.h; sourceTree = ""; }; + 2D9740419F0E776F1FABB904D5CA004A /* RKDictionaryUtilities.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKDictionaryUtilities.m; path = Code/Support/RKDictionaryUtilities.m; sourceTree = ""; }; + 2E6059501A894452C487FAD40EB578F6 /* SOCKit-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "SOCKit-prefix.pch"; sourceTree = ""; }; + 3201B0055A4CC8749A6C9573EB16F156 /* RKMappingResult.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKMappingResult.h; path = Code/ObjectMapping/RKMappingResult.h; sourceTree = ""; }; + 330A6D2DE7F31FDDC4FDF2BB3D2FB16F /* RKValueTransformers.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKValueTransformers.h; path = Code/RKValueTransformers.h; sourceTree = ""; }; + 355D30AA75F7200E1391EE2F9850AAFD /* RKConnectionDescription.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKConnectionDescription.m; path = Code/CoreData/RKConnectionDescription.m; sourceTree = ""; }; + 35DF21416621652AF45697AD1EE4C341 /* RKValueTransformers-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "RKValueTransformers-prefix.pch"; sourceTree = ""; }; + 36A53F844115F0FCFBC089F15BB2469C /* RKManagedObjectImporter.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKManagedObjectImporter.h; path = Code/CoreData/RKManagedObjectImporter.h; sourceTree = ""; }; + 3714579E6A77AF6BA29C2BF928C9B606 /* RKAttributeMapping.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKAttributeMapping.m; path = Code/ObjectMapping/RKAttributeMapping.m; sourceTree = ""; }; + 37F81F4EA220D0B72285D504A5F4F6AF /* AFHTTPRequestOperation.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = AFHTTPRequestOperation.h; path = AFNetworking/AFHTTPRequestOperation.h; sourceTree = ""; }; + 3817F79A2FFAFA957786169D44338961 /* ISO8601DateFormatterValueTransformer.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = ISO8601DateFormatterValueTransformer.h; path = Code/ISO8601DateFormatterValueTransformer.h; sourceTree = ""; }; + 3A52401BB23052568B1A947BBEDB306E /* RKMIMETypeSerialization.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKMIMETypeSerialization.m; path = Code/Support/RKMIMETypeSerialization.m; sourceTree = ""; }; + 3B111C75C47C01AD77014B63358CFC32 /* RKResponseMapperOperation.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKResponseMapperOperation.m; path = Code/Network/RKResponseMapperOperation.m; sourceTree = ""; }; + 3B56547657777695ED964437D29CF06F /* RKObjectUtilities.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKObjectUtilities.m; path = Code/ObjectMapping/RKObjectUtilities.m; sourceTree = ""; }; + 3C6363FD012D2047BA5E3D5721AA4283 /* RKInMemoryManagedObjectCache.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKInMemoryManagedObjectCache.m; path = Code/CoreData/RKInMemoryManagedObjectCache.m; sourceTree = ""; }; + 3C97F271E7936BA5558DA15DCCEEF5B4 /* RKMapping.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKMapping.h; path = Code/ObjectMapping/RKMapping.h; sourceTree = ""; }; + 3DEF5A2506038F276A17FD8EFD4250B5 /* RKURLEncodedSerialization.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKURLEncodedSerialization.h; path = Code/Support/RKURLEncodedSerialization.h; sourceTree = ""; }; + 3E8A0031D6B5F5BC3372D44FC206C3DD /* RKManagedObjectImporter.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKManagedObjectImporter.m; path = Code/CoreData/RKManagedObjectImporter.m; sourceTree = ""; }; + 40C40C0517D7C210D4A32215DEB225C1 /* TKEvent.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = TKEvent.h; path = Code/TKEvent.h; sourceTree = ""; }; + 41B98447BAE742CDDF19066AAC6AAC37 /* RKResponseMapperOperation.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKResponseMapperOperation.h; path = Code/Network/RKResponseMapperOperation.h; sourceTree = ""; }; + 421DCDF4B392934B3767CC0EFAC4B66C /* RKObjectManager.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKObjectManager.h; path = Code/Network/RKObjectManager.h; sourceTree = ""; }; + 4391678EE65327EC09710A2246AE3738 /* TKStateMachine.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = TKStateMachine.m; path = Code/TKStateMachine.m; sourceTree = ""; }; + 444FC2341F629885838C0D9C08592DA2 /* RKObjectMapping.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKObjectMapping.m; path = Code/ObjectMapping/RKObjectMapping.m; sourceTree = ""; }; + 46FB2E21EF84A959B269657382ED17C6 /* RKErrors.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKErrors.m; path = Code/Support/RKErrors.m; sourceTree = ""; }; + 4E37F47F8B8CC9C91B39061A7536E3E9 /* libTransitionKit.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libTransitionKit.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 4EEE3DF4039896AC75D7A94A0F772E64 /* RKManagedObjectMappingOperationDataSource.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKManagedObjectMappingOperationDataSource.m; path = Code/CoreData/RKManagedObjectMappingOperationDataSource.m; sourceTree = ""; }; + 4FE09EB1BAFD6593655A66644AD9F2C0 /* SOCKit-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "SOCKit-dummy.m"; sourceTree = ""; }; + 51FB5E1BA147BA2BF2006C014F98C0F4 /* RKManagedObjectStore.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKManagedObjectStore.h; path = Code/CoreData/RKManagedObjectStore.h; sourceTree = ""; }; + 5370AF9DFC5C717414F78FBE75FB86A3 /* RKRouter.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKRouter.m; path = Code/Network/RKRouter.m; sourceTree = ""; }; + 57B7FA85F7FF4BC986930EAF9AEB8AE4 /* RKSerialization.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKSerialization.h; path = Code/Support/RKSerialization.h; sourceTree = ""; }; + 58AE1A849FC8983D888E44BCBD097C46 /* RestKit.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = RestKit.xcconfig; sourceTree = ""; }; + 591F047DDB62DFE9714DB1BD18837A46 /* RKDotNetDateFormatter.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKDotNetDateFormatter.h; path = Code/Support/RKDotNetDateFormatter.h; sourceTree = ""; }; + 5A01AB4B80B7DCCB9F7C5C552E05BB8D /* RKManagedObjectStore.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKManagedObjectStore.m; path = Code/CoreData/RKManagedObjectStore.m; sourceTree = ""; }; + 5A96D00C413528D13CFFF3F98BA97ABF /* RKPropertyMapping.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKPropertyMapping.h; path = Code/ObjectMapping/RKPropertyMapping.h; sourceTree = ""; }; + 5B3A074303EE3BACB3EF55B454D5B75F /* SOCKit.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = SOCKit.xcconfig; sourceTree = ""; }; + 5F12E318CF57363604E63A8FD7E69CFE /* libPods.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPods.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 5F2C28CF81EE920F924A4832B385A2ED /* RKManagedObjectMappingOperationDataSource.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKManagedObjectMappingOperationDataSource.h; path = Code/CoreData/RKManagedObjectMappingOperationDataSource.h; sourceTree = ""; }; + 5FDC132C654FF745DD4CFC455B189BD4 /* RKPropertyInspector.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKPropertyInspector.m; path = Code/ObjectMapping/RKPropertyInspector.m; sourceTree = ""; }; + 6089BF8DFE413DFABE2316758D79A9E0 /* NSManagedObjectContext+RKAdditions.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "NSManagedObjectContext+RKAdditions.m"; path = "Code/CoreData/NSManagedObjectContext+RKAdditions.m"; sourceTree = ""; }; + 60A36A6CB5A18DCFF1C8BDEBF3DF48CE /* RKMapping.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKMapping.m; path = Code/ObjectMapping/RKMapping.m; sourceTree = ""; }; + 641AE05DD55E5E6AC1590CD7B4A18F97 /* Pods-resources.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-resources.sh"; sourceTree = ""; }; + 6775ABB2FDC1D38BB156811370A081BE /* RKObjectUtilities.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKObjectUtilities.h; path = Code/ObjectMapping/RKObjectUtilities.h; sourceTree = ""; }; + 67B224EC11AFE6EC20CAC138BAAB212C /* AFHTTPClient.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = AFHTTPClient.h; path = AFNetworking/AFHTTPClient.h; sourceTree = ""; }; + 68BB64A5DA74B805350B4DDCC2CEC42C /* RKFetchRequestManagedObjectCache.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKFetchRequestManagedObjectCache.m; path = Code/CoreData/RKFetchRequestManagedObjectCache.m; sourceTree = ""; }; + 69254A440F2B5109BFEBBB7F222C4E33 /* RKOperationStateMachine.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKOperationStateMachine.m; path = Code/Support/RKOperationStateMachine.m; sourceTree = ""; }; + 69812CA1FFB4AEEF65A7A3092671B5D0 /* AFHTTPRequestOperation.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = AFHTTPRequestOperation.m; path = AFNetworking/AFHTTPRequestOperation.m; sourceTree = ""; }; + 71F6AABF844EEFEB27E227BB0E2023EF /* RKMappingResult.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKMappingResult.m; path = Code/ObjectMapping/RKMappingResult.m; sourceTree = ""; }; + 73B51CD9C883E11B8078E0974C555E8C /* RKDictionaryUtilities.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKDictionaryUtilities.h; path = Code/Support/RKDictionaryUtilities.h; sourceTree = ""; }; + 74C927694DE2F40C7E060C2E5700792D /* RKPathUtilities.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKPathUtilities.h; path = Code/Support/RKPathUtilities.h; sourceTree = ""; }; + 76DAA4F1ED26D9A2EE4ED429C4B1C631 /* RKMIMETypeSerialization.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKMIMETypeSerialization.h; path = Code/Support/RKMIMETypeSerialization.h; sourceTree = ""; }; + 773888E56286AA8CFEABAB9CAFFE507C /* libRestKit.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRestKit.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 78615091D9077E11CDD208BB528484D0 /* RKManagedObjectCaching.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKManagedObjectCaching.h; path = Code/CoreData/RKManagedObjectCaching.h; sourceTree = ""; }; + 7A9005F420A97F873CC7908200857388 /* RKISO8601DateFormatter.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKISO8601DateFormatter.m; path = Code/RKISO8601DateFormatter.m; sourceTree = ""; }; + 7ACA953B4A5A3F0EE5C2B6ACBD46C246 /* GoogleMaps.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GoogleMaps.framework; path = Frameworks/GoogleMaps.framework; sourceTree = ""; }; + 7C2D775649F85A043CFE757B675E073F /* RestKit-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "RestKit-prefix.pch"; sourceTree = ""; }; + 7C4F5C9AE4AE536F4DDFC2AEE57F30F3 /* AFXMLRequestOperation.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = AFXMLRequestOperation.m; path = AFNetworking/AFXMLRequestOperation.m; sourceTree = ""; }; + 801774778ACB915E071F725B50208B91 /* RKMIMETypes.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKMIMETypes.h; path = Code/Support/RKMIMETypes.h; sourceTree = ""; }; + 8154C55352F65270356E82260D9D0BC6 /* RKISO8601DateFormatter.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKISO8601DateFormatter.h; path = Code/RKISO8601DateFormatter.h; sourceTree = ""; }; + 815E808EAA76782C0E2910798238C1CE /* RKRelationshipConnectionOperation.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKRelationshipConnectionOperation.m; path = Code/CoreData/RKRelationshipConnectionOperation.m; sourceTree = ""; }; + 825B0623122A3C6D3BDA5F37B8B9FE64 /* RKStringTokenizer.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKStringTokenizer.h; path = Code/Support/RKStringTokenizer.h; sourceTree = ""; }; + 82CAEF9FA55FE7D5E36A20E10D584C1C /* AFNetworkActivityIndicatorManager.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = AFNetworkActivityIndicatorManager.m; path = AFNetworking/AFNetworkActivityIndicatorManager.m; sourceTree = ""; }; + 83702DD2C5D49085FC3C98D95063C244 /* RKHTTPUtilities.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKHTTPUtilities.m; path = Code/ObjectMapping/RKHTTPUtilities.m; sourceTree = ""; }; + 8503AAFA23E65CD4CFC1BC142EF0880F /* AFJSONRequestOperation.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = AFJSONRequestOperation.m; path = AFNetworking/AFJSONRequestOperation.m; sourceTree = ""; }; + 86A7FF814F2BB8CE7941F41F4DB93D47 /* AFPropertyListRequestOperation.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = AFPropertyListRequestOperation.h; path = AFNetworking/AFPropertyListRequestOperation.h; sourceTree = ""; }; + 86BB61D2391D09636581699CCC11BC20 /* RKCoreData.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKCoreData.h; path = Code/CoreData/RKCoreData.h; sourceTree = ""; }; + 89622454B6309852AD9687B0820C02B0 /* SOCKit.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = SOCKit.m; sourceTree = ""; }; + 89771AEAB0B05F90650D107E81B24E15 /* lcl_RK.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = lcl_RK.h; path = Vendor/LibComponentLogging/Core/lcl_RK.h; sourceTree = ""; }; + 8A023459CEFDFF7132C0E8E5EA88B24D /* lcl_RK.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = lcl_RK.m; path = Vendor/LibComponentLogging/Core/lcl_RK.m; sourceTree = ""; }; + 8A370A0CBD0F14A336B48549716953A2 /* AFURLConnectionOperation.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = AFURLConnectionOperation.h; path = AFNetworking/AFURLConnectionOperation.h; sourceTree = ""; }; + 8A3CCA72533E35C4376B1E8AECC9627F /* TransitionKit.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = TransitionKit.h; path = Code/TransitionKit.h; sourceTree = ""; }; + 8B521FF0C82B79C4BA11F04BB245D3AD /* RKRequestDescriptor.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKRequestDescriptor.h; path = Code/Network/RKRequestDescriptor.h; sourceTree = ""; }; + 8B62D9AD5CDC11C216E0871A1E30CF16 /* RKMIMETypes.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKMIMETypes.m; path = Code/Support/RKMIMETypes.m; sourceTree = ""; }; + 8B93150D00B31A6AA70DB23B61FF989F /* RKObjectRequestOperation.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKObjectRequestOperation.m; path = Code/Network/RKObjectRequestOperation.m; sourceTree = ""; }; + 8DAAEB36FECEFA6C9F1BB99E284D129A /* RKValueTransformers.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = RKValueTransformers.xcconfig; sourceTree = ""; }; + 8EEB88C54F5131BB8ED29CC84ACEC0FD /* GoogleMaps.bundle */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = "wrapper.plug-in"; name = GoogleMaps.bundle; path = Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle; sourceTree = ""; }; + 913CE9ED58A6F60DDEA5AA890FF1F48C /* RKPropertyMapping.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKPropertyMapping.m; path = Code/ObjectMapping/RKPropertyMapping.m; sourceTree = ""; }; + 9218BCE40D1CE071C875CD2227624D65 /* RKDotNetDateFormatter.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKDotNetDateFormatter.m; path = Code/Support/RKDotNetDateFormatter.m; sourceTree = ""; }; + 943190F187AC5F8FB83B38BE9196CE1B /* AFNetworkActivityIndicatorManager.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = AFNetworkActivityIndicatorManager.h; path = AFNetworking/AFNetworkActivityIndicatorManager.h; sourceTree = ""; }; + 9502AACFA962A1F7AD805C8D0F0714EA /* RKPathUtilities.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKPathUtilities.m; path = Code/Support/RKPathUtilities.m; sourceTree = ""; }; + 96A98B34414903617DDCC4DD35D0ACC8 /* SOCKit.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = SOCKit.h; sourceTree = ""; }; + 96D5B99F66D4E009B90BD61EBF7408AB /* RKNSJSONSerialization.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKNSJSONSerialization.m; path = Code/Support/RKNSJSONSerialization.m; sourceTree = ""; }; + 97113E4E5D6665DA629C112370C7ADC2 /* RKLog.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKLog.h; path = Code/Support/RKLog.h; sourceTree = ""; }; + 9936ED8D363FA6B09EA60941182E9F3B /* TKState.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = TKState.m; path = Code/TKState.m; sourceTree = ""; }; + 9C4F9F2DEE9D79A1FF1CC7A48B5EFE10 /* RKRelationshipMapping.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKRelationshipMapping.h; path = Code/ObjectMapping/RKRelationshipMapping.h; sourceTree = ""; }; + 9F85354D369A63FDA2DD23B9DECB7FEF /* RKDynamicMapping.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKDynamicMapping.m; path = Code/ObjectMapping/RKDynamicMapping.m; sourceTree = ""; }; + A073456F96570555C23C9FC55D278495 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS8.3.sdk/System/Library/Frameworks/Security.framework; sourceTree = DEVELOPER_DIR; }; + A08639AFDB6619D2C8C75E2CA6E6FABA /* RKURLEncodedSerialization.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKURLEncodedSerialization.m; path = Code/Support/RKURLEncodedSerialization.m; sourceTree = ""; }; + A2602AEF93C48C7D094AC09E341D7EFB /* UIImageView+AFNetworking.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "UIImageView+AFNetworking.h"; path = "AFNetworking/UIImageView+AFNetworking.h"; sourceTree = ""; }; + A31828A6382DA55EF1EFE3884D70F53C /* ISO8601DateFormatterValueTransformer-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "ISO8601DateFormatterValueTransformer-prefix.pch"; sourceTree = ""; }; + A41B62B0D621AA6C11392F766FCD51FE /* AFImageRequestOperation.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = AFImageRequestOperation.m; path = AFNetworking/AFImageRequestOperation.m; sourceTree = ""; }; + A4F85A759F06DA2C165FC5F9C67479D9 /* TKState.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = TKState.h; path = Code/TKState.h; sourceTree = ""; }; + A54BA714770BA8ED007819BC352FEB7C /* libSOCKit.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libSOCKit.a; sourceTree = BUILT_PRODUCTS_DIR; }; + A5C79D0DA910AC71493B65AD46DBFB51 /* RKMapperOperation.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKMapperOperation.h; path = Code/ObjectMapping/RKMapperOperation.h; sourceTree = ""; }; + A74E5D8F04AA4E80349CCE11A4EABC2A /* RKPathMatcher.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKPathMatcher.h; path = Code/Network/RKPathMatcher.h; sourceTree = ""; }; + A7AA1C9D195A03A7CB6CCC4C59B24D75 /* AFHTTPClient.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = AFHTTPClient.m; path = AFNetworking/AFHTTPClient.m; sourceTree = ""; }; + A8FA5F2052C43B6E4060DAF60265E858 /* SOCKit-Private.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "SOCKit-Private.xcconfig"; sourceTree = ""; }; + AB2F08445612D3FEDB688B73B2B89289 /* NSManagedObject+RKAdditions.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "NSManagedObject+RKAdditions.h"; path = "Code/CoreData/NSManagedObject+RKAdditions.h"; sourceTree = ""; }; + AB33A5CB02849F1DE28836DEE20E225D /* RKRoute.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKRoute.m; path = Code/Network/RKRoute.m; sourceTree = ""; }; + AB5F89C2FF338EB3D8A14F31581D0B13 /* TransitionKit-Private.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "TransitionKit-Private.xcconfig"; sourceTree = ""; }; + AC66FDB9CE227CD408443442E71B4345 /* libAFNetworking.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libAFNetworking.a; sourceTree = BUILT_PRODUCTS_DIR; }; + ACAA32E0DD83A1EA3B8803214D102848 /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = Pods.release.xcconfig; sourceTree = ""; }; + ACB1E33D558E9F09939C382A52C6BF1F /* RKHTTPUtilities.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKHTTPUtilities.h; path = Code/ObjectMapping/RKHTTPUtilities.h; sourceTree = ""; }; + AE9B1AB727BB27D6269E9161365EBD5D /* Pods-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-dummy.m"; sourceTree = ""; }; + B12031C3E62BD36C971135BE9E4A8093 /* RKEntityByAttributeCache.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKEntityByAttributeCache.m; path = Code/CoreData/RKEntityByAttributeCache.m; sourceTree = ""; }; + B19EB35698C23661E2056A801F3CA85E /* RKManagedObjectRequestOperation.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKManagedObjectRequestOperation.m; path = Code/Network/RKManagedObjectRequestOperation.m; sourceTree = ""; }; + B2BADBAB5E57898066A5BF57C7711E8B /* RKHTTPRequestOperation.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKHTTPRequestOperation.h; path = Code/Network/RKHTTPRequestOperation.h; sourceTree = ""; }; + B594C1A9FEE6DB22895B832E9F44EA18 /* NSManagedObjectContext+RKAdditions.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "NSManagedObjectContext+RKAdditions.h"; path = "Code/CoreData/NSManagedObjectContext+RKAdditions.h"; sourceTree = ""; }; + B64181FBC7BDB50DE4A27D6DF07AD1A5 /* RKAttributeMapping.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKAttributeMapping.h; path = Code/ObjectMapping/RKAttributeMapping.h; sourceTree = ""; }; + B6B11130FEB122F4D5A3C9EF4765AAF7 /* lcl_config_extensions_RK.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = lcl_config_extensions_RK.h; path = Code/Support/lcl_config_extensions_RK.h; sourceTree = ""; }; + B82D087D1CB28D51874BC78E9E53CDED /* AFNetworking-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "AFNetworking-prefix.pch"; sourceTree = ""; }; + B855E065D967A0FB50C5E2EA494CC30E /* RKMapperOperation.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKMapperOperation.m; path = Code/ObjectMapping/RKMapperOperation.m; sourceTree = ""; }; + B963B3236B5FD7C7902A5D99E7F7E95B /* RKPathMatcher.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKPathMatcher.m; path = Code/Network/RKPathMatcher.m; sourceTree = ""; }; + BA457F3A2935EDA97B4CB28C14302B64 /* RKErrorMessage.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKErrorMessage.m; path = Code/ObjectMapping/RKErrorMessage.m; sourceTree = ""; }; + BA6428E9F66FD5A23C0A2E06ED26CD2F /* Podfile */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = Podfile; path = ../Podfile; sourceTree = SOURCE_ROOT; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; + BAE871BE7529E8BBB941E7EA5791C795 /* RKNSJSONSerialization.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKNSJSONSerialization.h; path = Code/Support/RKNSJSONSerialization.h; sourceTree = ""; }; + BAEBFACE85B965081E04ADDC13F2AB76 /* RKResponseDescriptor.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKResponseDescriptor.m; path = Code/Network/RKResponseDescriptor.m; sourceTree = ""; }; + BE2DEDDD86B0FA6D80CA5A041B52C16C /* RKEntityMapping.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKEntityMapping.m; path = Code/CoreData/RKEntityMapping.m; sourceTree = ""; }; + BF59BC15D23E1E1912C8F334E7236813 /* Pods-acknowledgements.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-acknowledgements.plist"; sourceTree = ""; }; + BFEAD72AC72B3A9784369FBA431D6AE0 /* RKValueTransformers-Private.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "RKValueTransformers-Private.xcconfig"; sourceTree = ""; }; + C1697E4A1C37410EA218CD801A3D8F96 /* RKObjectMappingOperationDataSource.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKObjectMappingOperationDataSource.m; path = Code/ObjectMapping/RKObjectMappingOperationDataSource.m; sourceTree = ""; }; + C19660B39C046CB326B68607FB0228FC /* RKDynamicMapping.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKDynamicMapping.h; path = Code/ObjectMapping/RKDynamicMapping.h; sourceTree = ""; }; + C1E8B6E7E8DC0CC43FFA833380380F29 /* AFNetworking.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = AFNetworking.xcconfig; sourceTree = ""; }; + C2E39A8AA6B454E44B785823DCAF4253 /* RKErrorMessage.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKErrorMessage.h; path = Code/ObjectMapping/RKErrorMessage.h; sourceTree = ""; }; + C4453AFB84A3DEAF1C42589840511DC4 /* AFPropertyListRequestOperation.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = AFPropertyListRequestOperation.m; path = AFNetworking/AFPropertyListRequestOperation.m; sourceTree = ""; }; + C70C9BCC7A26C68B1B5D686E6E44B247 /* AFURLConnectionOperation.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = AFURLConnectionOperation.m; path = AFNetworking/AFURLConnectionOperation.m; sourceTree = ""; }; + C7A3C431941CA5458B46FDA87ADD17E9 /* TKStateMachine.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = TKStateMachine.h; path = Code/TKStateMachine.h; sourceTree = ""; }; + C7EC6F2637B182461F70DECB756AB989 /* RKValueTransformers-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "RKValueTransformers-dummy.m"; sourceTree = ""; }; + C87B4270FD59E85DA2A1FB79F03BCED7 /* RKRoute.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKRoute.h; path = Code/Network/RKRoute.h; sourceTree = ""; }; + C8F26EB7600374EA1D6C8F7C5DF00858 /* TransitionKit.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = TransitionKit.xcconfig; sourceTree = ""; }; + CBEF069B1E72EBFC5D71A6048331803E /* libRKValueTransformers.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRKValueTransformers.a; sourceTree = BUILT_PRODUCTS_DIR; }; + CD92A31E153551EE24F6972E506E3984 /* RKInMemoryManagedObjectCache.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKInMemoryManagedObjectCache.h; path = Code/CoreData/RKInMemoryManagedObjectCache.h; sourceTree = ""; }; + CDFF065508A8C1CD3EA1AF5129DBBA29 /* libISO8601DateFormatterValueTransformer.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libISO8601DateFormatterValueTransformer.a; sourceTree = BUILT_PRODUCTS_DIR; }; + D0ABD79E3710B87422441144957CDE12 /* RKRouteSet.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKRouteSet.m; path = Code/Network/RKRouteSet.m; sourceTree = ""; }; + D11414CAE06B475EA350D0FEC33B4F7D /* RestKit-Private.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "RestKit-Private.xcconfig"; sourceTree = ""; }; + D359D03F6001570CBB455FAC918986F7 /* AFNetworking-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "AFNetworking-dummy.m"; sourceTree = ""; }; + D4C3531092980F15D05E364FF3F2135A /* ISO8601DateFormatterValueTransformer.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = ISO8601DateFormatterValueTransformer.xcconfig; sourceTree = ""; }; + D656844F12E1C432C199C2FAC5D3C060 /* NSManagedObject+RKAdditions.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "NSManagedObject+RKAdditions.m"; path = "Code/CoreData/NSManagedObject+RKAdditions.m"; sourceTree = ""; }; + D786CAF5775AD1EE25298FE83BCDC4FA /* RKStringTokenizer.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKStringTokenizer.m; path = Code/Support/RKStringTokenizer.m; sourceTree = ""; }; + D8BA0A77AD35E66CCC406CBCC9B63B7B /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS8.3.sdk/System/Library/Frameworks/CoreGraphics.framework; sourceTree = DEVELOPER_DIR; }; + DA9B5ECC134F1E032125D1094DE52029 /* AFXMLRequestOperation.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = AFXMLRequestOperation.h; path = AFNetworking/AFXMLRequestOperation.h; sourceTree = ""; }; + DB7BEEC0D36BBE2BA710A0AEB72C6340 /* RKValueTransformers.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKValueTransformers.m; path = Code/RKValueTransformers.m; sourceTree = ""; }; + DBC84FD9E910C0EA092051869B07A569 /* RKPropertyInspector+CoreData.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "RKPropertyInspector+CoreData.m"; path = "Code/CoreData/RKPropertyInspector+CoreData.m"; sourceTree = ""; }; + DC38339D1F6208C3F3EC097654FB5266 /* RKObjectParameterization.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKObjectParameterization.h; path = Code/Network/RKObjectParameterization.h; sourceTree = ""; }; + DE78C0DAAE0ECFC194E7F021969A990A /* RKEntityByAttributeCache.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKEntityByAttributeCache.h; path = Code/CoreData/RKEntityByAttributeCache.h; sourceTree = ""; }; + DF0F7A2381BDDF3CE3B4A6CE3B1DADBE /* RKEntityCache.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKEntityCache.m; path = Code/CoreData/RKEntityCache.m; sourceTree = ""; }; + E07CF80BF3E1F92CE6D27E5B54838452 /* RKObjectMappingOperationDataSource.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKObjectMappingOperationDataSource.h; path = Code/ObjectMapping/RKObjectMappingOperationDataSource.h; sourceTree = ""; }; + E19C172D35667648056819B35F7E7107 /* Support.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = Support.h; path = Code/Support.h; sourceTree = ""; }; + E1F53224DB5E88FC17699D7F693BC616 /* TransitionKit-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "TransitionKit-prefix.pch"; sourceTree = ""; }; + E2DD1C139C6511B2ED108234B26B3549 /* ISO8601DateFormatterValueTransformer.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = ISO8601DateFormatterValueTransformer.m; path = Code/ISO8601DateFormatterValueTransformer.m; sourceTree = ""; }; + E65C0BB8745BB49525AEBAFE8CBA3FC9 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS8.3.sdk/System/Library/Frameworks/CoreData.framework; sourceTree = DEVELOPER_DIR; }; + E7AF3A6C1F3EBBDDC45435DE443FB8D7 /* RKMacros.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKMacros.h; path = Code/Support/RKMacros.h; sourceTree = ""; }; + E8F3DFF4383693E425C06F36BFF9F034 /* Network.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = Network.h; path = Code/Network.h; sourceTree = ""; }; + E97048C221239B35B2B30FE746BA1B19 /* RKEntityCache.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKEntityCache.h; path = Code/CoreData/RKEntityCache.h; sourceTree = ""; }; + E98F870EB992340D88A021CF973C564D /* RKRelationshipConnectionOperation.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKRelationshipConnectionOperation.h; path = Code/CoreData/RKRelationshipConnectionOperation.h; sourceTree = ""; }; + E9BDA006E4FED9FEB5518B6D00A67263 /* RKHTTPRequestOperation.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKHTTPRequestOperation.m; path = Code/Network/RKHTTPRequestOperation.m; sourceTree = ""; }; + EBC5BB06AF51F439764DC4F5158ABC64 /* RKPaginator.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKPaginator.h; path = Code/Network/RKPaginator.h; sourceTree = ""; }; + EBEDF339EF5DF85BC77639D611E818B8 /* RKMappingOperation.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKMappingOperation.m; path = Code/ObjectMapping/RKMappingOperation.m; sourceTree = ""; }; + ECBC1A0C2A02762F1E83F3050A46FBEF /* RKObjectRequestOperation.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKObjectRequestOperation.h; path = Code/Network/RKObjectRequestOperation.h; sourceTree = ""; }; + EE78A9B6E3722476ED12EDAAF4C9C2E8 /* AFNetworking.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = AFNetworking.h; path = AFNetworking/AFNetworking.h; sourceTree = ""; }; + EF788416FA16290F6645BCE0435437AE /* RKPaginator.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKPaginator.m; path = Code/Network/RKPaginator.m; sourceTree = ""; }; + EF8D331ECDED3685C263A77DDC1C1106 /* RKObjectParameterization.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKObjectParameterization.m; path = Code/Network/RKObjectParameterization.m; sourceTree = ""; }; + F0CB4E3EC1ACD76F2309A54B490DF091 /* TKTransition.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = TKTransition.h; path = Code/TKTransition.h; sourceTree = ""; }; + F4846409FD18BF8B96FF09787A484C30 /* AFNetworking-Private.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "AFNetworking-Private.xcconfig"; sourceTree = ""; }; + F5328AD4D1FFC55D735BE48F5E658C13 /* RKEntityMapping.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RKEntityMapping.h; path = Code/CoreData/RKEntityMapping.h; sourceTree = ""; }; + F5CE8BC88F72A12FE1283DBF0A070E89 /* RKRequestDescriptor.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKRequestDescriptor.m; path = Code/Network/RKRequestDescriptor.m; sourceTree = ""; }; + FA1E66EECB2CCEA42260109F42EBA268 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS8.3.sdk/System/Library/Frameworks/SystemConfiguration.framework; sourceTree = DEVELOPER_DIR; }; + FBCDACF4953305A48F143D830F6A8B33 /* RKLumberjackLogger.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = RKLumberjackLogger.m; path = Code/Support/RKLumberjackLogger.m; sourceTree = ""; }; + FBD6BCC976E19538049A41A68497F025 /* RestKit-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "RestKit-dummy.m"; sourceTree = ""; }; + FBFBD757BF729B37665318B9758927C8 /* MobileCoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MobileCoreServices.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS8.3.sdk/System/Library/Frameworks/MobileCoreServices.framework; sourceTree = DEVELOPER_DIR; }; + FC74CBE84F5FC2A1D0685071DB3F820E /* CoreData.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = CoreData.h; path = Code/CoreData.h; sourceTree = ""; }; + FC8E48FFBC54C4B5596828D905E3BC9D /* ISO8601DateFormatterValueTransformer-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "ISO8601DateFormatterValueTransformer-dummy.m"; sourceTree = ""; }; + FE3330F6814BB0DD40B5BF23DDB44CEA /* UIImageView+AFNetworking.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "UIImageView+AFNetworking.m"; path = "AFNetworking/UIImageView+AFNetworking.m"; sourceTree = ""; }; + FE59913ED3A4732BB41A9091E0CE1831 /* AFImageRequestOperation.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = AFImageRequestOperation.h; path = AFNetworking/AFImageRequestOperation.h; sourceTree = ""; }; + FE8E6A9A05AB1426D9E86AAC2DDDB14E /* CFNetwork.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CFNetwork.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS8.3.sdk/System/Library/Frameworks/CFNetwork.framework; sourceTree = DEVELOPER_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 0AECA54A8A2E44A0EFA0AA67F6203343 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + A695A94853169B3E07FE3343C48A8E05 /* CFNetwork.framework in Frameworks */, + D6C012BA03CA2D817494AC42792C4C0D /* CoreData.framework in Frameworks */, + 55EF216D5857AA144044D9373EC2643B /* Foundation.framework in Frameworks */, + A93C5853F5BE181FB80CDF8C1189AD18 /* MobileCoreServices.framework in Frameworks */, + FDCABAF695F563402D326C91601BB0A0 /* Security.framework in Frameworks */, + 003922F3F435C70F3059B35631F20291 /* SystemConfiguration.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 2AC391C828BA63A98AE89E2337D4FAE8 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 3117F1F1B481FC575970F85E2770EAE2 /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 50BA29B9194194F4809BD2743D2352E9 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + E0A877FEF013CFE5C85881F1E3B8EEB7 /* CoreGraphics.framework in Frameworks */, + 42FE9F2674F4A05270725F0985349D4C /* Foundation.framework in Frameworks */, + 5D57EC90E127CF3481FFEF4BF3169769 /* MobileCoreServices.framework in Frameworks */, + 13354F84F76DBA512EEC93E1BE523B3B /* Security.framework in Frameworks */, + 6E7E825054211CBFB06A7F065E772FFE /* SystemConfiguration.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5972652DA8E3CB6256417EE7BCB541BA /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + C2406F161CC120D07B885E6D8D930DB3 /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 67CFF8AD8DC741D9FD2BA13A98B8BEF0 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 8FE5788EF14F6E44BD11EA5B8C3C1587 /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 6B5D18067C9B73911CE61A64AF4C99C3 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + A2C5AE290D32BB07ADBC57590BF79B8B /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 9DC969F730A7AF73AC05D90B1F238415 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + B97F7A2BA951D87E943FFE51C6D1721D /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 04FCF669427FC70DDBBD63F8DF5767A2 /* AFNetworking */ = { + isa = PBXGroup; + children = ( + 67B224EC11AFE6EC20CAC138BAAB212C /* AFHTTPClient.h */, + A7AA1C9D195A03A7CB6CCC4C59B24D75 /* AFHTTPClient.m */, + 37F81F4EA220D0B72285D504A5F4F6AF /* AFHTTPRequestOperation.h */, + 69812CA1FFB4AEEF65A7A3092671B5D0 /* AFHTTPRequestOperation.m */, + FE59913ED3A4732BB41A9091E0CE1831 /* AFImageRequestOperation.h */, + A41B62B0D621AA6C11392F766FCD51FE /* AFImageRequestOperation.m */, + 1CF18DCA5EB135C7FB73BCD5A881765B /* AFJSONRequestOperation.h */, + 8503AAFA23E65CD4CFC1BC142EF0880F /* AFJSONRequestOperation.m */, + 943190F187AC5F8FB83B38BE9196CE1B /* AFNetworkActivityIndicatorManager.h */, + 82CAEF9FA55FE7D5E36A20E10D584C1C /* AFNetworkActivityIndicatorManager.m */, + EE78A9B6E3722476ED12EDAAF4C9C2E8 /* AFNetworking.h */, + 86A7FF814F2BB8CE7941F41F4DB93D47 /* AFPropertyListRequestOperation.h */, + C4453AFB84A3DEAF1C42589840511DC4 /* AFPropertyListRequestOperation.m */, + 8A370A0CBD0F14A336B48549716953A2 /* AFURLConnectionOperation.h */, + C70C9BCC7A26C68B1B5D686E6E44B247 /* AFURLConnectionOperation.m */, + DA9B5ECC134F1E032125D1094DE52029 /* AFXMLRequestOperation.h */, + 7C4F5C9AE4AE536F4DDFC2AEE57F30F3 /* AFXMLRequestOperation.m */, + A2602AEF93C48C7D094AC09E341D7EFB /* UIImageView+AFNetworking.h */, + FE3330F6814BB0DD40B5BF23DDB44CEA /* UIImageView+AFNetworking.m */, + 90D35CA525ED0AD41B533D561BFE92E1 /* Support Files */, + ); + path = AFNetworking; + sourceTree = ""; + }; + 0EBDC67CC8A60029EE09B104A9008308 /* TransitionKit */ = { + isa = PBXGroup; + children = ( + 40C40C0517D7C210D4A32215DEB225C1 /* TKEvent.h */, + 02B4ADB1ECAC920122E657AE18B10BFE /* TKEvent.m */, + A4F85A759F06DA2C165FC5F9C67479D9 /* TKState.h */, + 9936ED8D363FA6B09EA60941182E9F3B /* TKState.m */, + C7A3C431941CA5458B46FDA87ADD17E9 /* TKStateMachine.h */, + 4391678EE65327EC09710A2246AE3738 /* TKStateMachine.m */, + F0CB4E3EC1ACD76F2309A54B490DF091 /* TKTransition.h */, + 2A2306F062D21537BCCD17B8E1265AE8 /* TKTransition.m */, + 8A3CCA72533E35C4376B1E8AECC9627F /* TransitionKit.h */, + 76AA7B9072EE6C3A4DC518D7619941F3 /* Support Files */, + ); + path = TransitionKit; + sourceTree = ""; + }; + 349CB3080DAC0B8924AFB06775098E95 /* ISO8601DateFormatterValueTransformer */ = { + isa = PBXGroup; + children = ( + 3817F79A2FFAFA957786169D44338961 /* ISO8601DateFormatterValueTransformer.h */, + E2DD1C139C6511B2ED108234B26B3549 /* ISO8601DateFormatterValueTransformer.m */, + 8154C55352F65270356E82260D9D0BC6 /* RKISO8601DateFormatter.h */, + 7A9005F420A97F873CC7908200857388 /* RKISO8601DateFormatter.m */, + C83CC7BED7C6F4667FBD07C3AC914C30 /* Support Files */, + ); + path = ISO8601DateFormatterValueTransformer; + sourceTree = ""; + }; + 351FDEDF7F9FAE5E6C4A135DCBCE5873 /* GoogleMaps */ = { + isa = PBXGroup; + children = ( + 4CFE7F585752D562E890FECA6B37168D /* Frameworks */, + 58BACB7D04A74C7BA3CC497288CBC638 /* Resources */, + ); + path = GoogleMaps; + sourceTree = ""; + }; + 353D309E651192CC2E914011FF095869 /* Support */ = { + isa = PBXGroup; + children = ( + 73B51CD9C883E11B8078E0974C555E8C /* RKDictionaryUtilities.h */, + 2D9740419F0E776F1FABB904D5CA004A /* RKDictionaryUtilities.m */, + 591F047DDB62DFE9714DB1BD18837A46 /* RKDotNetDateFormatter.h */, + 9218BCE40D1CE071C875CD2227624D65 /* RKDotNetDateFormatter.m */, + 0A4F9CA2983FD37B4A2F2C3FB29F6469 /* RKErrors.h */, + 46FB2E21EF84A959B269657382ED17C6 /* RKErrors.m */, + 97113E4E5D6665DA629C112370C7ADC2 /* RKLog.h */, + 03D7C131287E9EB129ECA49C0C3BC29D /* RKLog.m */, + 1CE577C871C6339B325216DAA1E9C380 /* RKLumberjackLogger.h */, + FBCDACF4953305A48F143D830F6A8B33 /* RKLumberjackLogger.m */, + 76DAA4F1ED26D9A2EE4ED429C4B1C631 /* RKMIMETypeSerialization.h */, + 3A52401BB23052568B1A947BBEDB306E /* RKMIMETypeSerialization.m */, + 801774778ACB915E071F725B50208B91 /* RKMIMETypes.h */, + 8B62D9AD5CDC11C216E0871A1E30CF16 /* RKMIMETypes.m */, + E7AF3A6C1F3EBBDDC45435DE443FB8D7 /* RKMacros.h */, + BAE871BE7529E8BBB941E7EA5791C795 /* RKNSJSONSerialization.h */, + 96D5B99F66D4E009B90BD61EBF7408AB /* RKNSJSONSerialization.m */, + 0EF40613DF53B1FB6902B2CAC50A651E /* RKOperationStateMachine.h */, + 69254A440F2B5109BFEBBB7F222C4E33 /* RKOperationStateMachine.m */, + 74C927694DE2F40C7E060C2E5700792D /* RKPathUtilities.h */, + 9502AACFA962A1F7AD805C8D0F0714EA /* RKPathUtilities.m */, + 57B7FA85F7FF4BC986930EAF9AEB8AE4 /* RKSerialization.h */, + 825B0623122A3C6D3BDA5F37B8B9FE64 /* RKStringTokenizer.h */, + D786CAF5775AD1EE25298FE83BCDC4FA /* RKStringTokenizer.m */, + 3DEF5A2506038F276A17FD8EFD4250B5 /* RKURLEncodedSerialization.h */, + A08639AFDB6619D2C8C75E2CA6E6FABA /* RKURLEncodedSerialization.m */, + 2C0BDC65F8FF87BF77753725100E83D1 /* RestKit.h */, + E19C172D35667648056819B35F7E7107 /* Support.h */, + 89771AEAB0B05F90650D107E81B24E15 /* lcl_RK.h */, + 8A023459CEFDFF7132C0E8E5EA88B24D /* lcl_RK.m */, + 00171B758ECFF00C265F2EA583C95CA4 /* lcl_config_components_RK.h */, + B6B11130FEB122F4D5A3C9EF4765AAF7 /* lcl_config_extensions_RK.h */, + 2496B383543745B1828664CEF6069019 /* lcl_config_logger_RK.h */, + ); + name = Support; + sourceTree = ""; + }; + 47FB2259E7871DC24922877130A9C9CD /* RKValueTransformers */ = { + isa = PBXGroup; + children = ( + 330A6D2DE7F31FDDC4FDF2BB3D2FB16F /* RKValueTransformers.h */, + DB7BEEC0D36BBE2BA710A0AEB72C6340 /* RKValueTransformers.m */, + EBFF9A44874A702EC5EA07FAACD9E37C /* Support Files */, + ); + path = RKValueTransformers; + sourceTree = ""; + }; + 4A94988794759E6A17A5DF8123306CD1 /* Support Files */ = { + isa = PBXGroup; + children = ( + 58AE1A849FC8983D888E44BCBD097C46 /* RestKit.xcconfig */, + D11414CAE06B475EA350D0FEC33B4F7D /* RestKit-Private.xcconfig */, + FBD6BCC976E19538049A41A68497F025 /* RestKit-dummy.m */, + 7C2D775649F85A043CFE757B675E073F /* RestKit-prefix.pch */, + ); + name = "Support Files"; + path = "../Target Support Files/RestKit"; + sourceTree = ""; + }; + 4AC2E55DED422A5DFABD1B2962FD50F7 /* Network */ = { + isa = PBXGroup; + children = ( + E8F3DFF4383693E425C06F36BFF9F034 /* Network.h */, + B2BADBAB5E57898066A5BF57C7711E8B /* RKHTTPRequestOperation.h */, + E9BDA006E4FED9FEB5518B6D00A67263 /* RKHTTPRequestOperation.m */, + 14D546CDCEF1964FA21938D1D24E0A61 /* RKManagedObjectRequestOperation.h */, + B19EB35698C23661E2056A801F3CA85E /* RKManagedObjectRequestOperation.m */, + 421DCDF4B392934B3767CC0EFAC4B66C /* RKObjectManager.h */, + 10D586F7993E35ECFE908332BCAD8D7A /* RKObjectManager.m */, + DC38339D1F6208C3F3EC097654FB5266 /* RKObjectParameterization.h */, + EF8D331ECDED3685C263A77DDC1C1106 /* RKObjectParameterization.m */, + ECBC1A0C2A02762F1E83F3050A46FBEF /* RKObjectRequestOperation.h */, + 8B93150D00B31A6AA70DB23B61FF989F /* RKObjectRequestOperation.m */, + 177CA429DCED072B6E1AE95498045736 /* RKObjectRequestOperationSubclass.h */, + EBC5BB06AF51F439764DC4F5158ABC64 /* RKPaginator.h */, + EF788416FA16290F6645BCE0435437AE /* RKPaginator.m */, + A74E5D8F04AA4E80349CCE11A4EABC2A /* RKPathMatcher.h */, + B963B3236B5FD7C7902A5D99E7F7E95B /* RKPathMatcher.m */, + 8B521FF0C82B79C4BA11F04BB245D3AD /* RKRequestDescriptor.h */, + F5CE8BC88F72A12FE1283DBF0A070E89 /* RKRequestDescriptor.m */, + 2C0ECC4F6DF50C1021A4526C66DAFFA8 /* RKResponseDescriptor.h */, + BAEBFACE85B965081E04ADDC13F2AB76 /* RKResponseDescriptor.m */, + 41B98447BAE742CDDF19066AAC6AAC37 /* RKResponseMapperOperation.h */, + 3B111C75C47C01AD77014B63358CFC32 /* RKResponseMapperOperation.m */, + C87B4270FD59E85DA2A1FB79F03BCED7 /* RKRoute.h */, + AB33A5CB02849F1DE28836DEE20E225D /* RKRoute.m */, + 20DA68ADE311D013F09FE151A3792BBA /* RKRouteSet.h */, + D0ABD79E3710B87422441144957CDE12 /* RKRouteSet.m */, + 09E4F74A52C00EF1C720E047C359B03F /* RKRouter.h */, + 5370AF9DFC5C717414F78FBE75FB86A3 /* RKRouter.m */, + ); + name = Network; + sourceTree = ""; + }; + 4CFE7F585752D562E890FECA6B37168D /* Frameworks */ = { + isa = PBXGroup; + children = ( + 7ACA953B4A5A3F0EE5C2B6ACBD46C246 /* GoogleMaps.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 58BACB7D04A74C7BA3CC497288CBC638 /* Resources */ = { + isa = PBXGroup; + children = ( + 8EEB88C54F5131BB8ED29CC84ACEC0FD /* GoogleMaps.bundle */, + ); + name = Resources; + sourceTree = ""; + }; + 59FF158D25C70DC3626DECF8C2C94120 /* CoreData */ = { + isa = PBXGroup; + children = ( + FC74CBE84F5FC2A1D0685071DB3F820E /* CoreData.h */, + AB2F08445612D3FEDB688B73B2B89289 /* NSManagedObject+RKAdditions.h */, + D656844F12E1C432C199C2FAC5D3C060 /* NSManagedObject+RKAdditions.m */, + B594C1A9FEE6DB22895B832E9F44EA18 /* NSManagedObjectContext+RKAdditions.h */, + 6089BF8DFE413DFABE2316758D79A9E0 /* NSManagedObjectContext+RKAdditions.m */, + 288DCADD78B9359AC1A27B99DDACC512 /* RKConnectionDescription.h */, + 355D30AA75F7200E1391EE2F9850AAFD /* RKConnectionDescription.m */, + 86BB61D2391D09636581699CCC11BC20 /* RKCoreData.h */, + DE78C0DAAE0ECFC194E7F021969A990A /* RKEntityByAttributeCache.h */, + B12031C3E62BD36C971135BE9E4A8093 /* RKEntityByAttributeCache.m */, + E97048C221239B35B2B30FE746BA1B19 /* RKEntityCache.h */, + DF0F7A2381BDDF3CE3B4A6CE3B1DADBE /* RKEntityCache.m */, + F5328AD4D1FFC55D735BE48F5E658C13 /* RKEntityMapping.h */, + BE2DEDDD86B0FA6D80CA5A041B52C16C /* RKEntityMapping.m */, + 26209DEBD0F8891CB1E2A68269B24B3F /* RKFetchRequestManagedObjectCache.h */, + 68BB64A5DA74B805350B4DDCC2CEC42C /* RKFetchRequestManagedObjectCache.m */, + CD92A31E153551EE24F6972E506E3984 /* RKInMemoryManagedObjectCache.h */, + 3C6363FD012D2047BA5E3D5721AA4283 /* RKInMemoryManagedObjectCache.m */, + 78615091D9077E11CDD208BB528484D0 /* RKManagedObjectCaching.h */, + 36A53F844115F0FCFBC089F15BB2469C /* RKManagedObjectImporter.h */, + 3E8A0031D6B5F5BC3372D44FC206C3DD /* RKManagedObjectImporter.m */, + 5F2C28CF81EE920F924A4832B385A2ED /* RKManagedObjectMappingOperationDataSource.h */, + 4EEE3DF4039896AC75D7A94A0F772E64 /* RKManagedObjectMappingOperationDataSource.m */, + 51FB5E1BA147BA2BF2006C014F98C0F4 /* RKManagedObjectStore.h */, + 5A01AB4B80B7DCCB9F7C5C552E05BB8D /* RKManagedObjectStore.m */, + 1BC614B568932C16177C4FAF9CCEF03C /* RKPropertyInspector+CoreData.h */, + DBC84FD9E910C0EA092051869B07A569 /* RKPropertyInspector+CoreData.m */, + E98F870EB992340D88A021CF973C564D /* RKRelationshipConnectionOperation.h */, + 815E808EAA76782C0E2910798238C1CE /* RKRelationshipConnectionOperation.m */, + ); + name = CoreData; + sourceTree = ""; + }; + 638F7155FE2E8526816D884E79C93BC3 /* RestKit */ = { + isa = PBXGroup; + children = ( + 59FF158D25C70DC3626DECF8C2C94120 /* CoreData */, + 4AC2E55DED422A5DFABD1B2962FD50F7 /* Network */, + FACA3FADF531DB7D8BB9ADEE2ED98A37 /* ObjectMapping */, + 353D309E651192CC2E914011FF095869 /* Support */, + 4A94988794759E6A17A5DF8123306CD1 /* Support Files */, + ); + path = RestKit; + sourceTree = ""; + }; + 76AA7B9072EE6C3A4DC518D7619941F3 /* Support Files */ = { + isa = PBXGroup; + children = ( + C8F26EB7600374EA1D6C8F7C5DF00858 /* TransitionKit.xcconfig */, + AB5F89C2FF338EB3D8A14F31581D0B13 /* TransitionKit-Private.xcconfig */, + 15854EBB45118A734AE77C8EFB408F10 /* TransitionKit-dummy.m */, + E1F53224DB5E88FC17699D7F693BC616 /* TransitionKit-prefix.pch */, + ); + name = "Support Files"; + path = "../Target Support Files/TransitionKit"; + sourceTree = ""; + }; + 7DB346D0F39D3F0E887471402A8071AB = { + isa = PBXGroup; + children = ( + BA6428E9F66FD5A23C0A2E06ED26CD2F /* Podfile */, + F4CDA5FA9197A41E0081E84F932906EB /* Frameworks */, + D7ECB1AA953C4B8B8B9D99500A66A5AB /* Pods */, + CCA510CFBEA2D207524CDA0D73C3B561 /* Products */, + D2411A5FE7F7A004607BED49990C37F4 /* Targets Support Files */, + ); + sourceTree = ""; + }; + 801355008DF19A1F65025B390D97EE42 /* Support Files */ = { + isa = PBXGroup; + children = ( + 5B3A074303EE3BACB3EF55B454D5B75F /* SOCKit.xcconfig */, + A8FA5F2052C43B6E4060DAF60265E858 /* SOCKit-Private.xcconfig */, + 4FE09EB1BAFD6593655A66644AD9F2C0 /* SOCKit-dummy.m */, + 2E6059501A894452C487FAD40EB578F6 /* SOCKit-prefix.pch */, + ); + name = "Support Files"; + path = "../Target Support Files/SOCKit"; + sourceTree = ""; + }; + 864650598425410E8E85058EB6293EDF /* SOCKit */ = { + isa = PBXGroup; + children = ( + 96A98B34414903617DDCC4DD35D0ACC8 /* SOCKit.h */, + 89622454B6309852AD9687B0820C02B0 /* SOCKit.m */, + 801355008DF19A1F65025B390D97EE42 /* Support Files */, + ); + path = SOCKit; + sourceTree = ""; + }; + 90D35CA525ED0AD41B533D561BFE92E1 /* Support Files */ = { + isa = PBXGroup; + children = ( + C1E8B6E7E8DC0CC43FFA833380380F29 /* AFNetworking.xcconfig */, + F4846409FD18BF8B96FF09787A484C30 /* AFNetworking-Private.xcconfig */, + D359D03F6001570CBB455FAC918986F7 /* AFNetworking-dummy.m */, + B82D087D1CB28D51874BC78E9E53CDED /* AFNetworking-prefix.pch */, + ); + name = "Support Files"; + path = "../Target Support Files/AFNetworking"; + sourceTree = ""; + }; + 952EEBFAF8F7E620423C9F156F25A506 /* Pods */ = { + isa = PBXGroup; + children = ( + 15A529C27057E4A57D259CBC6E6CE49C /* Pods-acknowledgements.markdown */, + BF59BC15D23E1E1912C8F334E7236813 /* Pods-acknowledgements.plist */, + AE9B1AB727BB27D6269E9161365EBD5D /* Pods-dummy.m */, + 641AE05DD55E5E6AC1590CD7B4A18F97 /* Pods-resources.sh */, + 18AB07DED7A12D04EC0629B6FD0986D6 /* Pods.debug.xcconfig */, + ACAA32E0DD83A1EA3B8803214D102848 /* Pods.release.xcconfig */, + ); + name = Pods; + path = "Target Support Files/Pods"; + sourceTree = ""; + }; + C165491CA8EB3737AE36C27FF4435400 /* iOS */ = { + isa = PBXGroup; + children = ( + FE8E6A9A05AB1426D9E86AAC2DDDB14E /* CFNetwork.framework */, + E65C0BB8745BB49525AEBAFE8CBA3FC9 /* CoreData.framework */, + D8BA0A77AD35E66CCC406CBCC9B63B7B /* CoreGraphics.framework */, + 2763EF8A157B940CA30BFB421AC0ABA8 /* Foundation.framework */, + FBFBD757BF729B37665318B9758927C8 /* MobileCoreServices.framework */, + A073456F96570555C23C9FC55D278495 /* Security.framework */, + FA1E66EECB2CCEA42260109F42EBA268 /* SystemConfiguration.framework */, + ); + name = iOS; + sourceTree = ""; + }; + C83CC7BED7C6F4667FBD07C3AC914C30 /* Support Files */ = { + isa = PBXGroup; + children = ( + D4C3531092980F15D05E364FF3F2135A /* ISO8601DateFormatterValueTransformer.xcconfig */, + 1B06BC7B07CE59865D25EF74E0EBA495 /* ISO8601DateFormatterValueTransformer-Private.xcconfig */, + FC8E48FFBC54C4B5596828D905E3BC9D /* ISO8601DateFormatterValueTransformer-dummy.m */, + A31828A6382DA55EF1EFE3884D70F53C /* ISO8601DateFormatterValueTransformer-prefix.pch */, + ); + name = "Support Files"; + path = "../Target Support Files/ISO8601DateFormatterValueTransformer"; + sourceTree = ""; + }; + CCA510CFBEA2D207524CDA0D73C3B561 /* Products */ = { + isa = PBXGroup; + children = ( + AC66FDB9CE227CD408443442E71B4345 /* libAFNetworking.a */, + CDFF065508A8C1CD3EA1AF5129DBBA29 /* libISO8601DateFormatterValueTransformer.a */, + 5F12E318CF57363604E63A8FD7E69CFE /* libPods.a */, + CBEF069B1E72EBFC5D71A6048331803E /* libRKValueTransformers.a */, + 773888E56286AA8CFEABAB9CAFFE507C /* libRestKit.a */, + A54BA714770BA8ED007819BC352FEB7C /* libSOCKit.a */, + 4E37F47F8B8CC9C91B39061A7536E3E9 /* libTransitionKit.a */, + ); + name = Products; + sourceTree = ""; + }; + D2411A5FE7F7A004607BED49990C37F4 /* Targets Support Files */ = { + isa = PBXGroup; + children = ( + 952EEBFAF8F7E620423C9F156F25A506 /* Pods */, + ); + name = "Targets Support Files"; + sourceTree = ""; + }; + D7ECB1AA953C4B8B8B9D99500A66A5AB /* Pods */ = { + isa = PBXGroup; + children = ( + 04FCF669427FC70DDBBD63F8DF5767A2 /* AFNetworking */, + 351FDEDF7F9FAE5E6C4A135DCBCE5873 /* GoogleMaps */, + 349CB3080DAC0B8924AFB06775098E95 /* ISO8601DateFormatterValueTransformer */, + 47FB2259E7871DC24922877130A9C9CD /* RKValueTransformers */, + 638F7155FE2E8526816D884E79C93BC3 /* RestKit */, + 864650598425410E8E85058EB6293EDF /* SOCKit */, + 0EBDC67CC8A60029EE09B104A9008308 /* TransitionKit */, + ); + name = Pods; + sourceTree = ""; + }; + EBFF9A44874A702EC5EA07FAACD9E37C /* Support Files */ = { + isa = PBXGroup; + children = ( + 8DAAEB36FECEFA6C9F1BB99E284D129A /* RKValueTransformers.xcconfig */, + BFEAD72AC72B3A9784369FBA431D6AE0 /* RKValueTransformers-Private.xcconfig */, + C7EC6F2637B182461F70DECB756AB989 /* RKValueTransformers-dummy.m */, + 35DF21416621652AF45697AD1EE4C341 /* RKValueTransformers-prefix.pch */, + ); + name = "Support Files"; + path = "../Target Support Files/RKValueTransformers"; + sourceTree = ""; + }; + F4CDA5FA9197A41E0081E84F932906EB /* Frameworks */ = { + isa = PBXGroup; + children = ( + C165491CA8EB3737AE36C27FF4435400 /* iOS */, + ); + name = Frameworks; + sourceTree = ""; + }; + FACA3FADF531DB7D8BB9ADEE2ED98A37 /* ObjectMapping */ = { + isa = PBXGroup; + children = ( + 0033106B5FFABEDBCF4AA601848E6A80 /* ObjectMapping.h */, + B64181FBC7BDB50DE4A27D6DF07AD1A5 /* RKAttributeMapping.h */, + 3714579E6A77AF6BA29C2BF928C9B606 /* RKAttributeMapping.m */, + C19660B39C046CB326B68607FB0228FC /* RKDynamicMapping.h */, + 9F85354D369A63FDA2DD23B9DECB7FEF /* RKDynamicMapping.m */, + C2E39A8AA6B454E44B785823DCAF4253 /* RKErrorMessage.h */, + BA457F3A2935EDA97B4CB28C14302B64 /* RKErrorMessage.m */, + ACB1E33D558E9F09939C382A52C6BF1F /* RKHTTPUtilities.h */, + 83702DD2C5D49085FC3C98D95063C244 /* RKHTTPUtilities.m */, + A5C79D0DA910AC71493B65AD46DBFB51 /* RKMapperOperation.h */, + B855E065D967A0FB50C5E2EA494CC30E /* RKMapperOperation.m */, + 1F862DAA8C5D3F9A21B8FDD6DBB5BE92 /* RKMapperOperation_Private.h */, + 3C97F271E7936BA5558DA15DCCEEF5B4 /* RKMapping.h */, + 60A36A6CB5A18DCFF1C8BDEBF3DF48CE /* RKMapping.m */, + 0138C2B05B8104023FA70A92886EF7AA /* RKMappingErrors.h */, + 1F8A9AA5696F58812E15720C7188EE1C /* RKMappingOperation.h */, + EBEDF339EF5DF85BC77639D611E818B8 /* RKMappingOperation.m */, + 2D5FBCC9C173CC91E1FCAF4635AD656D /* RKMappingOperationDataSource.h */, + 3201B0055A4CC8749A6C9573EB16F156 /* RKMappingResult.h */, + 71F6AABF844EEFEB27E227BB0E2023EF /* RKMappingResult.m */, + 10E7656293309EA130C59D062696C0E8 /* RKObjectMapping.h */, + 444FC2341F629885838C0D9C08592DA2 /* RKObjectMapping.m */, + 20D708DAD41809C2158DF41AED4C2D4E /* RKObjectMappingMatcher.h */, + 075FCDDF36844F6C78BF403DD8A12FE8 /* RKObjectMappingMatcher.m */, + E07CF80BF3E1F92CE6D27E5B54838452 /* RKObjectMappingOperationDataSource.h */, + C1697E4A1C37410EA218CD801A3D8F96 /* RKObjectMappingOperationDataSource.m */, + 6775ABB2FDC1D38BB156811370A081BE /* RKObjectUtilities.h */, + 3B56547657777695ED964437D29CF06F /* RKObjectUtilities.m */, + 1C2727A5C3ED5938FF430DC0A3D84E14 /* RKPropertyInspector.h */, + 5FDC132C654FF745DD4CFC455B189BD4 /* RKPropertyInspector.m */, + 5A96D00C413528D13CFFF3F98BA97ABF /* RKPropertyMapping.h */, + 913CE9ED58A6F60DDEA5AA890FF1F48C /* RKPropertyMapping.m */, + 9C4F9F2DEE9D79A1FF1CC7A48B5EFE10 /* RKRelationshipMapping.h */, + 27FB687584CA64BD1F2AAE24301EE980 /* RKRelationshipMapping.m */, + ); + name = ObjectMapping; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 34C00F8CAA4133FBBA432B273E1D4AD6 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + D25C7E2A0C55DA3A31BF7E091A1F8E2F /* CoreData.h in Headers */, + 09C078638B2314EDC932C7F8F610E764 /* NSManagedObject+RKAdditions.h in Headers */, + A8C7AF57E9E8301BBBD2328F099C23A3 /* NSManagedObjectContext+RKAdditions.h in Headers */, + 804DCE62D40FDE2DCB87C6B561C3CF8E /* Network.h in Headers */, + 9C79801284A040CF9286B70FD0E49711 /* ObjectMapping.h in Headers */, + F001896C78D171217E39EF32BA9115CF /* RKAttributeMapping.h in Headers */, + 5E98FDFF26CDAF1425208820335CB061 /* RKConnectionDescription.h in Headers */, + 4D11949A5ED3449CBBA01F8B379C9977 /* RKCoreData.h in Headers */, + 84545A853EB47D7A15412CAEF81691FC /* RKDictionaryUtilities.h in Headers */, + D28C93C0AB9A00F114622E3A574AF13E /* RKDotNetDateFormatter.h in Headers */, + B3A2CFAB459DD270F6C9ED1ED3116C3A /* RKDynamicMapping.h in Headers */, + 19D70B83BF8F0332A162228223EA92FB /* RKEntityByAttributeCache.h in Headers */, + 9C41DECE303A7A43376A55CEF2FBCE95 /* RKEntityCache.h in Headers */, + 843F7238D7686D3EDF2A512BEB56D348 /* RKEntityMapping.h in Headers */, + A07A8D5FC4840F776938B60C6FB246EC /* RKErrorMessage.h in Headers */, + EDDC5483CF7756F74426BDA53D7605C8 /* RKErrors.h in Headers */, + 1AAABDEF9A1A58A790D2A024BB2DE56F /* RKFetchRequestManagedObjectCache.h in Headers */, + 2C7FBD7862DF7ED7977D53138646053B /* RKHTTPRequestOperation.h in Headers */, + CCAF5CC514337B555C6902351DF5FA77 /* RKHTTPUtilities.h in Headers */, + 8627F96A7A43B5FC7AD9681E5FE53DD5 /* RKInMemoryManagedObjectCache.h in Headers */, + DF07D77FAF571E4C4BA7E60AE18C3B7C /* RKLog.h in Headers */, + 02FC94B48589009C42B710CF70B8D5DF /* RKLumberjackLogger.h in Headers */, + DE47E4EC28D55D67ACE12C085797C928 /* RKMIMETypeSerialization.h in Headers */, + B0F14B6E203AC5C434348441B36A2722 /* RKMIMETypes.h in Headers */, + 4DF3134DB56A588569FEC601E6885010 /* RKMacros.h in Headers */, + 64BE1EE97C0B7E4AA6DD31FE41225E5D /* RKManagedObjectCaching.h in Headers */, + D7806799BEF42E3AF9F018EB11A24AC6 /* RKManagedObjectImporter.h in Headers */, + 05AE8098E6A68548AE55F558538DA530 /* RKManagedObjectMappingOperationDataSource.h in Headers */, + 06418D23A05B289562DC2DD4D7B81478 /* RKManagedObjectRequestOperation.h in Headers */, + 6C98A7F2659D90328BE72A5884878347 /* RKManagedObjectStore.h in Headers */, + 186C04D79AC22AE39323DF7CDCB5EAD5 /* RKMapperOperation.h in Headers */, + 72BE31A2DBBAF59C41F07D54ACF19682 /* RKMapperOperation_Private.h in Headers */, + ED4C390C6C06B4305A562B7B6FCCF56B /* RKMapping.h in Headers */, + A4285902E75A9B36452F261732169903 /* RKMappingErrors.h in Headers */, + 213FF46BFDA397F7626AF1B49D55956A /* RKMappingOperation.h in Headers */, + 19F14817D21FB3495F930C964111B9A4 /* RKMappingOperationDataSource.h in Headers */, + A8AEF0B683BD5849CD69DDFB593970C6 /* RKMappingResult.h in Headers */, + FF31D1A15BFB36959A7E06B5BF7EBD95 /* RKNSJSONSerialization.h in Headers */, + 95E280925ADF11A0BA7F705C1885F5DC /* RKObjectManager.h in Headers */, + BA8C9A927C8E7BAD715C1EEF7ACDA79B /* RKObjectMapping.h in Headers */, + AF5121CEE8BC0D2D902659375844C937 /* RKObjectMappingMatcher.h in Headers */, + F88CBAF955FEB5A51E24E84A207F8F44 /* RKObjectMappingOperationDataSource.h in Headers */, + 3CFE326D184C35F88BDE3AF58A47B589 /* RKObjectParameterization.h in Headers */, + 511BBAAC3058BA57EDC0A144BC1EC9B1 /* RKObjectRequestOperation.h in Headers */, + B3A6803F1565A9C7CE4DE075228F8617 /* RKObjectRequestOperationSubclass.h in Headers */, + 387A32E066C413938EE3DF87F73F1495 /* RKObjectUtilities.h in Headers */, + 4B59AEDB18E741D6254C5BFEACF87FE9 /* RKOperationStateMachine.h in Headers */, + F575760612D781DD6E76347739392D2A /* RKPaginator.h in Headers */, + 1FF3660FAF22C06576FC1D0012129E02 /* RKPathMatcher.h in Headers */, + DD4C9BA231F24DF9A87997EBCB14A8AC /* RKPathUtilities.h in Headers */, + A265586D9672B0A78DA648653B24B0C3 /* RKPropertyInspector+CoreData.h in Headers */, + 5B41FABAD8E3D8448EB80144DE05162A /* RKPropertyInspector.h in Headers */, + A553464682FB751898EE249DD887C975 /* RKPropertyMapping.h in Headers */, + 82A9639187AD655DF78D741C32B97F25 /* RKRelationshipConnectionOperation.h in Headers */, + EFE3090E2529A4E4ABF8C2ECF0A47669 /* RKRelationshipMapping.h in Headers */, + 955AF3408EE35750E3097FF257EF1C4C /* RKRequestDescriptor.h in Headers */, + 65396D00CDC745B51EB42B92A9510A12 /* RKResponseDescriptor.h in Headers */, + AC66A0C3B2CD40FAF63B969C22002667 /* RKResponseMapperOperation.h in Headers */, + 0EF36DBD862CFA8CD361D4A78233C472 /* RKRoute.h in Headers */, + D2CC9690359AFF7318391ACDDAC1C48A /* RKRouteSet.h in Headers */, + 696C46EE2CFB740888793208E42B25C0 /* RKRouter.h in Headers */, + 235FB2009F139FF0D6D9732295B6B165 /* RKSerialization.h in Headers */, + 48E2BA503D8ECCF77AC0EC3366459A07 /* RKStringTokenizer.h in Headers */, + 53D8A6C1F5BE588CCD5A070405A17BA8 /* RKURLEncodedSerialization.h in Headers */, + 9F3446FD81B98C845E0DAFDD62913FDB /* RestKit.h in Headers */, + E492215BF50305DBA7E7CD90763D8757 /* Support.h in Headers */, + C731F1A9652EB02201D53C378E3AECD9 /* lcl_RK.h in Headers */, + 602B1446FAA28671D5D1338EEEC09C1F /* lcl_config_components_RK.h in Headers */, + 66468A541A9F0EB06E0FBB97539562E3 /* lcl_config_extensions_RK.h in Headers */, + 1C6C78E700C93A3F406847A8DE335052 /* lcl_config_logger_RK.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 6017EC60669E37EA5D4E28DEC7D0D802 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + B22432E8FC8424E1514FA26CD8DF29A8 /* RKValueTransformers.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 8AAB5C9C35D21E7DE9BABB9F3AE359CA /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 44EEBB71B919C890EC133515DAADA53E /* SOCKit.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D20BF03AA59C506A4D5AA6791C98E606 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + AAE115E50155948641D97F4C4782327B /* TKEvent.h in Headers */, + 73FD34365A5B80EC64B0B5A8E99AF46E /* TKState.h in Headers */, + AEF152DEB9D69B47F9BBF7E427E90A0E /* TKStateMachine.h in Headers */, + 99F872BB5976264AD7648F8F8252D8B5 /* TKTransition.h in Headers */, + 8526C9EF4EE664BFA507C921AFACEF23 /* TransitionKit.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + E0C19CB873356835EF52CAF8B5DA68D6 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + AFDA7900BE8CA77BB17C961E3BC02958 /* AFHTTPClient.h in Headers */, + 07074DCE20E9D5E18C47C82C7BE85512 /* AFHTTPRequestOperation.h in Headers */, + 3C3C6A6F18D48756F82A928065F9EE95 /* AFImageRequestOperation.h in Headers */, + CC8EE054A94737C7B6463B66AB5D7F35 /* AFJSONRequestOperation.h in Headers */, + CBC217725771FAA918C235535861F443 /* AFNetworkActivityIndicatorManager.h in Headers */, + CCEEC74BF5A6249F43B8FD40FAA4AC54 /* AFNetworking.h in Headers */, + A5BE02D3806FDB367A4129949CCC7567 /* AFPropertyListRequestOperation.h in Headers */, + 9D1CFCDA0AD746AEC3349E5EFFF0729B /* AFURLConnectionOperation.h in Headers */, + B384C39C1181D85CCFA031C87CC35DA8 /* AFXMLRequestOperation.h in Headers */, + E1E7DE5CD1C45C66F68446702EB588BF /* UIImageView+AFNetworking.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + FF1DC5E6F3BAE0E116DA36BC303016E9 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 60D6622FFAFF8C593110C093AA5AE054 /* ISO8601DateFormatterValueTransformer.h in Headers */, + AB2FFBD48FA0942C55246A46CED2C9E9 /* RKISO8601DateFormatter.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 01ACB00BFF1DE54BD7E0D352C57CE9FB /* ISO8601DateFormatterValueTransformer */ = { + isa = PBXNativeTarget; + buildConfigurationList = 18F35DD29D9851E4DF6D21F71EC89D16 /* Build configuration list for PBXNativeTarget "ISO8601DateFormatterValueTransformer" */; + buildPhases = ( + 198A2D390AB4B8C03937DD014CDB2F37 /* Sources */, + 2AC391C828BA63A98AE89E2337D4FAE8 /* Frameworks */, + FF1DC5E6F3BAE0E116DA36BC303016E9 /* Headers */, + ); + buildRules = ( + ); + dependencies = ( + E4FF87BDD425BE8D1D68E37475728949 /* PBXTargetDependency */, + ); + name = ISO8601DateFormatterValueTransformer; + productName = ISO8601DateFormatterValueTransformer; + productReference = CDFF065508A8C1CD3EA1AF5129DBBA29 /* libISO8601DateFormatterValueTransformer.a */; + productType = "com.apple.product-type.library.static"; + }; + 1327E0781EB2B6ED635FBE8AA187DBC6 /* Pods */ = { + isa = PBXNativeTarget; + buildConfigurationList = 9685A47F63B7FC550A1C98681CED4385 /* Build configuration list for PBXNativeTarget "Pods" */; + buildPhases = ( + 9E41BF1782D4323865AB390727F62154 /* Sources */, + 6B5D18067C9B73911CE61A64AF4C99C3 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + E1F2984D817CF7E85D8A080C1122090C /* PBXTargetDependency */, + D39C9E61C60216C2CCE727F6534FF257 /* PBXTargetDependency */, + 30194063A7E4DF42F7743BD4838844A5 /* PBXTargetDependency */, + EC630979ADC2043D361F391D397F998A /* PBXTargetDependency */, + A810D6D55F514553E40EF9CDB3B0400B /* PBXTargetDependency */, + 85DA049E2BA8DCECE9709E7028768FA9 /* PBXTargetDependency */, + ); + name = Pods; + productName = Pods; + productReference = 5F12E318CF57363604E63A8FD7E69CFE /* libPods.a */; + productType = "com.apple.product-type.library.static"; + }; + 158117D77AED03B83733E51D2D22983B /* TransitionKit */ = { + isa = PBXNativeTarget; + buildConfigurationList = EC5884D823C95D73657B127F496ED2E3 /* Build configuration list for PBXNativeTarget "TransitionKit" */; + buildPhases = ( + 3F093A1EE91BCE92AFC73A3B72540240 /* Sources */, + 67CFF8AD8DC741D9FD2BA13A98B8BEF0 /* Frameworks */, + D20BF03AA59C506A4D5AA6791C98E606 /* Headers */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = TransitionKit; + productName = TransitionKit; + productReference = 4E37F47F8B8CC9C91B39061A7536E3E9 /* libTransitionKit.a */; + productType = "com.apple.product-type.library.static"; + }; + 68E291FC1F64705132E3A6E596659EB8 /* RestKit */ = { + isa = PBXNativeTarget; + buildConfigurationList = A765DCCE51BB64312BB4FFF99B73EE53 /* Build configuration list for PBXNativeTarget "RestKit" */; + buildPhases = ( + EB4BF9B499961AC208D959D6B14B3868 /* Sources */, + 0AECA54A8A2E44A0EFA0AA67F6203343 /* Frameworks */, + 34C00F8CAA4133FBBA432B273E1D4AD6 /* Headers */, + ); + buildRules = ( + ); + dependencies = ( + 42F1A0A0EB3411A1969E1E215C6B6C1D /* PBXTargetDependency */, + 9DF1B45B78CFAFAFF60429E8998A5403 /* PBXTargetDependency */, + C203599C1808C5BD397C4974F7530B7F /* PBXTargetDependency */, + D0076B5156305FB1ED76A81A70B60D9C /* PBXTargetDependency */, + 04266E6CB3E1C04B49BAB7AF5F28CAD3 /* PBXTargetDependency */, + ); + name = RestKit; + productName = RestKit; + productReference = 773888E56286AA8CFEABAB9CAFFE507C /* libRestKit.a */; + productType = "com.apple.product-type.library.static"; + }; + A2770197345BCE1622568AECE6B8E824 /* SOCKit */ = { + isa = PBXNativeTarget; + buildConfigurationList = BE9B407615E85CA189C0133A977CB6E4 /* Build configuration list for PBXNativeTarget "SOCKit" */; + buildPhases = ( + 3B27D6A53A40DB67B708280465D0F21C /* Sources */, + 5972652DA8E3CB6256417EE7BCB541BA /* Frameworks */, + 8AAB5C9C35D21E7DE9BABB9F3AE359CA /* Headers */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = SOCKit; + productName = SOCKit; + productReference = A54BA714770BA8ED007819BC352FEB7C /* libSOCKit.a */; + productType = "com.apple.product-type.library.static"; + }; + C22CB88F290EB94BA5BAC35D7486F902 /* AFNetworking */ = { + isa = PBXNativeTarget; + buildConfigurationList = 7CEBC4DE609364610411675E3F25820C /* Build configuration list for PBXNativeTarget "AFNetworking" */; + buildPhases = ( + 1B46F572C8BECBED981D0EE082B4508B /* Sources */, + 50BA29B9194194F4809BD2743D2352E9 /* Frameworks */, + E0C19CB873356835EF52CAF8B5DA68D6 /* Headers */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = AFNetworking; + productName = AFNetworking; + productReference = AC66FDB9CE227CD408443442E71B4345 /* libAFNetworking.a */; + productType = "com.apple.product-type.library.static"; + }; + ECE37F5BCF4EB1F3EFFB3120C3ACA70E /* RKValueTransformers */ = { + isa = PBXNativeTarget; + buildConfigurationList = 59A0920A53C9D5A501168E60A7BFECD3 /* Build configuration list for PBXNativeTarget "RKValueTransformers" */; + buildPhases = ( + D7E78AB3B4CDCB43C8BC6397F19E0598 /* Sources */, + 9DC969F730A7AF73AC05D90B1F238415 /* Frameworks */, + 6017EC60669E37EA5D4E28DEC7D0D802 /* Headers */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = RKValueTransformers; + productName = RKValueTransformers; + productReference = CBEF069B1E72EBFC5D71A6048331803E /* libRKValueTransformers.a */; + productType = "com.apple.product-type.library.static"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + D41D8CD98F00B204E9800998ECF8427E /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0700; + LastUpgradeCheck = 0700; + }; + buildConfigurationList = 2D8E8EC45A3A1A1D94AE762CB5028504 /* Build configuration list for PBXProject "Pods" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = 7DB346D0F39D3F0E887471402A8071AB; + productRefGroup = CCA510CFBEA2D207524CDA0D73C3B561 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + C22CB88F290EB94BA5BAC35D7486F902 /* AFNetworking */, + 01ACB00BFF1DE54BD7E0D352C57CE9FB /* ISO8601DateFormatterValueTransformer */, + 1327E0781EB2B6ED635FBE8AA187DBC6 /* Pods */, + ECE37F5BCF4EB1F3EFFB3120C3ACA70E /* RKValueTransformers */, + 68E291FC1F64705132E3A6E596659EB8 /* RestKit */, + A2770197345BCE1622568AECE6B8E824 /* SOCKit */, + 158117D77AED03B83733E51D2D22983B /* TransitionKit */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + 198A2D390AB4B8C03937DD014CDB2F37 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 98295AD03AB36FD9257B157FF62B2579 /* ISO8601DateFormatterValueTransformer-dummy.m in Sources */, + A433A73D0FBCFE93C944C162548EA55C /* ISO8601DateFormatterValueTransformer.m in Sources */, + E35137B0D3B508DB7280840288E1EADE /* RKISO8601DateFormatter.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 1B46F572C8BECBED981D0EE082B4508B /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 471DA3AA75BA868460EF227585BBD852 /* AFHTTPClient.m in Sources */, + F8EBD2043BE81FB6479A46064E538E3E /* AFHTTPRequestOperation.m in Sources */, + 77D9A95773F05BD98ECED9F3C2D04F51 /* AFImageRequestOperation.m in Sources */, + 2C9C9BEB619088543C81B35B355E573D /* AFJSONRequestOperation.m in Sources */, + 0C5F579A13AD494E6D548F0C0953EAD9 /* AFNetworkActivityIndicatorManager.m in Sources */, + 4B6DB470CB0437173A8ACF0A346DAC20 /* AFNetworking-dummy.m in Sources */, + 159FBA2393B76374AC530CA087152929 /* AFPropertyListRequestOperation.m in Sources */, + C375D977229721851615EB9E33421C78 /* AFURLConnectionOperation.m in Sources */, + E3765B1D38848D947246248A47761767 /* AFXMLRequestOperation.m in Sources */, + 510E66C0F3C15C63E813B43B6D299F00 /* UIImageView+AFNetworking.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 3B27D6A53A40DB67B708280465D0F21C /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + AED7DD46159F1525CBAED2B765B6FBB2 /* SOCKit-dummy.m in Sources */, + EB73AF4C9D61D61F7B1BB0F6C573118D /* SOCKit.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 3F093A1EE91BCE92AFC73A3B72540240 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 4443DA164C04807EF22B9E2FE3A40CEE /* TKEvent.m in Sources */, + FD2144C4BC84FA87FB99AF5DF4A659D4 /* TKState.m in Sources */, + 0722E90FFB0E0659D82D8E560CA2D2F1 /* TKStateMachine.m in Sources */, + EABAE5228ACD4A5BE6F30A53F80B9C1E /* TKTransition.m in Sources */, + B8291EBC0CA538454602E54BDA92A1B7 /* TransitionKit-dummy.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 9E41BF1782D4323865AB390727F62154 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 4311F0AAEBACD972A3BCA0A1F375257D /* Pods-dummy.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D7E78AB3B4CDCB43C8BC6397F19E0598 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ECFD9B44DF6C09FB22CAE869501E019C /* RKValueTransformers-dummy.m in Sources */, + 06FBDBD1B1926434DEB60A12D8D94788 /* RKValueTransformers.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + EB4BF9B499961AC208D959D6B14B3868 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 9CD9F914F536E8DE8E6155BDC5791E4D /* NSManagedObject+RKAdditions.m in Sources */, + A3325C43A0153A8D78947A8AEA9889E9 /* NSManagedObjectContext+RKAdditions.m in Sources */, + 3C5A2533640256DFA4741B3BF70CB471 /* RKAttributeMapping.m in Sources */, + 00159301B6C98C7E2CEF4BEA9E1B45A8 /* RKConnectionDescription.m in Sources */, + 26915C193CCB7FF7AC7444ACAB49F23B /* RKDictionaryUtilities.m in Sources */, + 17740E8D1F9A01D5E9D01B5D4A049AAA /* RKDotNetDateFormatter.m in Sources */, + C35137BF1721ED975122EFB940442BE4 /* RKDynamicMapping.m in Sources */, + 0BBA7C712421887DDD5B27A1E1CA5086 /* RKEntityByAttributeCache.m in Sources */, + 921F52B8F7CAA90D61666CD8529416E6 /* RKEntityCache.m in Sources */, + 7D614D2691101C18B40ED2D26F9B1D01 /* RKEntityMapping.m in Sources */, + 22A54BDE1E03FC728A1B8095A6CAC7A2 /* RKErrorMessage.m in Sources */, + 9F1A9CCF11D95B355DBD688895AFAB0C /* RKErrors.m in Sources */, + 45A721C168090AABDE63D52EED273D7E /* RKFetchRequestManagedObjectCache.m in Sources */, + 484A53B1B043BE7E8D7C98CE6CE11D6F /* RKHTTPRequestOperation.m in Sources */, + 44FD0F553976021B8ECF5C1822266ABA /* RKHTTPUtilities.m in Sources */, + F70C49E01E12EBB037350F95EA1AA195 /* RKInMemoryManagedObjectCache.m in Sources */, + E22A1B2C2827AB6E7FEC96DF736CD35F /* RKLog.m in Sources */, + 09A4819C981D051CF3CF4D383AF60C19 /* RKLumberjackLogger.m in Sources */, + DC86E3F27825FE1DC63AD5036D9D8975 /* RKMIMETypeSerialization.m in Sources */, + A59FDF68B16F36F332C84BCED4B56A9A /* RKMIMETypes.m in Sources */, + D593064CDF2BF18F89534B515B6EF07E /* RKManagedObjectImporter.m in Sources */, + 11D168CB2159ED3CBF8C46EBFFAB9375 /* RKManagedObjectMappingOperationDataSource.m in Sources */, + A83AD78FED2B02AE79871685A11FBA76 /* RKManagedObjectRequestOperation.m in Sources */, + A138C9CC8F1734DC526276C176875C94 /* RKManagedObjectStore.m in Sources */, + 16D390EF5962B18B3398279A5794C35A /* RKMapperOperation.m in Sources */, + 413589AC9FD0D5E6381069D6D8456B33 /* RKMapping.m in Sources */, + A14E1DB45EA2308F962F434472960DF8 /* RKMappingOperation.m in Sources */, + C586ECC71F71C909A4BF55ADEBAA0B86 /* RKMappingResult.m in Sources */, + 7BE64592FA01CC5C59B9E77C1A22DACB /* RKNSJSONSerialization.m in Sources */, + DDF4A5DDE3524075CD8B2CD3F500C7B8 /* RKObjectManager.m in Sources */, + 493D2A390E73C85B5D7D90A40BF2A52B /* RKObjectMapping.m in Sources */, + 67A779BC3625EFF978BB358B8BECDD3D /* RKObjectMappingMatcher.m in Sources */, + 5D0EDEA52D1557387DC0F127C0607C8E /* RKObjectMappingOperationDataSource.m in Sources */, + 5FE47AF12D37691C922FF07F36E472D9 /* RKObjectParameterization.m in Sources */, + 631C2D635D055B906CDAF4DF48800C54 /* RKObjectRequestOperation.m in Sources */, + 9CA67BACED9C9D40AE7B87ED3B1F39D6 /* RKObjectUtilities.m in Sources */, + 28D1EB89FFFEC1A2428C054E6DE77D39 /* RKOperationStateMachine.m in Sources */, + 2785DDF6BEDB173C21ABB64AE5E6D70A /* RKPaginator.m in Sources */, + 8528D500AF6F16347DBB2A9AB5C17684 /* RKPathMatcher.m in Sources */, + B51FF19CCD1732C53786D1FA1D7A414F /* RKPathUtilities.m in Sources */, + 8E5D38FD317C57488B159F49FD3A8CCC /* RKPropertyInspector+CoreData.m in Sources */, + AE61F69B4265A18A01C3E0E7333F8DA4 /* RKPropertyInspector.m in Sources */, + 6C16B969866DB74F5BA4BB69E70A7CD0 /* RKPropertyMapping.m in Sources */, + BF6090929BE8D0BDFE25DC50BB59C698 /* RKRelationshipConnectionOperation.m in Sources */, + 75C23CBCDF34BCBAD7EBF64991F23EE3 /* RKRelationshipMapping.m in Sources */, + B7D1E227311A8524D25969B0E3A3C7ED /* RKRequestDescriptor.m in Sources */, + 8CFF8AAB18381D4BB6731F0C88B997E6 /* RKResponseDescriptor.m in Sources */, + B28FCECFA61DD7C62C8D719CB6F0A4C0 /* RKResponseMapperOperation.m in Sources */, + A812943B1CC510887FA5A5D029C87A08 /* RKRoute.m in Sources */, + D9CF2FCF96A7E4AC565DAD67A8A8E0BE /* RKRouteSet.m in Sources */, + C2A46EF6A663BC8C3ACFEE6CBE3FAFEB /* RKRouter.m in Sources */, + FB8ABED36262DF148645FEAAD7C2AB4A /* RKStringTokenizer.m in Sources */, + B0C6E840F6C838687FD759E421F8DDE8 /* RKURLEncodedSerialization.m in Sources */, + 6B8655482FEEB3176CC12ED2D76FD5A4 /* RestKit-dummy.m in Sources */, + 2F1F6FA5BF85956CEC4E228790D1CA2F /* lcl_RK.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 04266E6CB3E1C04B49BAB7AF5F28CAD3 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = TransitionKit; + target = 158117D77AED03B83733E51D2D22983B /* TransitionKit */; + targetProxy = 7B43A77C8F316F3CD803CA70E1AB057D /* PBXContainerItemProxy */; + }; + 30194063A7E4DF42F7743BD4838844A5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = RKValueTransformers; + target = ECE37F5BCF4EB1F3EFFB3120C3ACA70E /* RKValueTransformers */; + targetProxy = E35A79A65CE187002FBE64125A9ED690 /* PBXContainerItemProxy */; + }; + 42F1A0A0EB3411A1969E1E215C6B6C1D /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = AFNetworking; + target = C22CB88F290EB94BA5BAC35D7486F902 /* AFNetworking */; + targetProxy = 55D0DD33832EAFE92A120CC597EAF3B2 /* PBXContainerItemProxy */; + }; + 85DA049E2BA8DCECE9709E7028768FA9 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = TransitionKit; + target = 158117D77AED03B83733E51D2D22983B /* TransitionKit */; + targetProxy = F95EB63EB8212CE724F4F1108117A90D /* PBXContainerItemProxy */; + }; + 9DF1B45B78CFAFAFF60429E8998A5403 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = ISO8601DateFormatterValueTransformer; + target = 01ACB00BFF1DE54BD7E0D352C57CE9FB /* ISO8601DateFormatterValueTransformer */; + targetProxy = CD584120AE4E2B56F0E00BFB2F0F6097 /* PBXContainerItemProxy */; + }; + A810D6D55F514553E40EF9CDB3B0400B /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = SOCKit; + target = A2770197345BCE1622568AECE6B8E824 /* SOCKit */; + targetProxy = 73806796ABDE6BBFA1A787DD54BB4254 /* PBXContainerItemProxy */; + }; + C203599C1808C5BD397C4974F7530B7F /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = RKValueTransformers; + target = ECE37F5BCF4EB1F3EFFB3120C3ACA70E /* RKValueTransformers */; + targetProxy = 4E98C56CA9779ADCB3C61F7A1F1AFF83 /* PBXContainerItemProxy */; + }; + D0076B5156305FB1ED76A81A70B60D9C /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = SOCKit; + target = A2770197345BCE1622568AECE6B8E824 /* SOCKit */; + targetProxy = D0CC65BEE6F2E3790A7B387750C819B3 /* PBXContainerItemProxy */; + }; + D39C9E61C60216C2CCE727F6534FF257 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = ISO8601DateFormatterValueTransformer; + target = 01ACB00BFF1DE54BD7E0D352C57CE9FB /* ISO8601DateFormatterValueTransformer */; + targetProxy = 688D88C28B6DCB5E8C32094C2EA431CF /* PBXContainerItemProxy */; + }; + E1F2984D817CF7E85D8A080C1122090C /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = AFNetworking; + target = C22CB88F290EB94BA5BAC35D7486F902 /* AFNetworking */; + targetProxy = B02D98F422302D691069C8B16D8E9D9E /* PBXContainerItemProxy */; + }; + E4FF87BDD425BE8D1D68E37475728949 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = RKValueTransformers; + target = ECE37F5BCF4EB1F3EFFB3120C3ACA70E /* RKValueTransformers */; + targetProxy = 80DD835A894C2B3C5172A736DF792F09 /* PBXContainerItemProxy */; + }; + EC630979ADC2043D361F391D397F998A /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = RestKit; + target = 68E291FC1F64705132E3A6E596659EB8 /* RestKit */; + targetProxy = 8D73036BA3F631512E91F45A23C95546 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + 0AE57E2375439BB6B92C8ACA957B94B9 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 1B06BC7B07CE59865D25EF74E0EBA495 /* ISO8601DateFormatterValueTransformer-Private.xcconfig */; + buildSettings = { + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_PREFIX_HEADER = "Target Support Files/ISO8601DateFormatterValueTransformer/ISO8601DateFormatterValueTransformer-prefix.pch"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = NO; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + }; + name = Release; + }; + 0DFFD5B377646ECA2B3EEEEA5D08A669 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = D11414CAE06B475EA350D0FEC33B4F7D /* RestKit-Private.xcconfig */; + buildSettings = { + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_PREFIX_HEADER = "Target Support Files/RestKit/RestKit-prefix.pch"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = NO; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + }; + name = Release; + }; + 1613D299E6C12EC750981F72447F2D39 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = AB5F89C2FF338EB3D8A14F31581D0B13 /* TransitionKit-Private.xcconfig */; + buildSettings = { + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_PREFIX_HEADER = "Target Support Files/TransitionKit/TransitionKit-prefix.pch"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = NO; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + }; + name = Release; + }; + 23B0CABDC81D3EA9DDBC33F608A3E401 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 18AB07DED7A12D04EC0629B6FD0986D6 /* Pods.debug.xcconfig */; + buildSettings = { + ENABLE_STRICT_OBJC_MSGSEND = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = YES; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PODS_ROOT = "$(SRCROOT)"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + }; + name = Debug; + }; + 279359901DDD3907B0016EBAFE7F2AE7 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = BFEAD72AC72B3A9784369FBA431D6AE0 /* RKValueTransformers-Private.xcconfig */; + buildSettings = { + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_PREFIX_HEADER = "Target Support Files/RKValueTransformers/RKValueTransformers-prefix.pch"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = NO; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + }; + name = Release; + }; + 3320DEEF5B3226617E9C30F1A64C7A32 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = BFEAD72AC72B3A9784369FBA431D6AE0 /* RKValueTransformers-Private.xcconfig */; + buildSettings = { + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_PREFIX_HEADER = "Target Support Files/RKValueTransformers/RKValueTransformers-prefix.pch"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = YES; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + }; + name = Debug; + }; + 39EE36124B77E37BCF8ADE16B77E7F16 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = F4846409FD18BF8B96FF09787A484C30 /* AFNetworking-Private.xcconfig */; + buildSettings = { + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_PREFIX_HEADER = "Target Support Files/AFNetworking/AFNetworking-prefix.pch"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = YES; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + }; + name = Debug; + }; + 53118C6292C556E93925B2081981B36B /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 1B06BC7B07CE59865D25EF74E0EBA495 /* ISO8601DateFormatterValueTransformer-Private.xcconfig */; + buildSettings = { + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_PREFIX_HEADER = "Target Support Files/ISO8601DateFormatterValueTransformer/ISO8601DateFormatterValueTransformer-prefix.pch"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = YES; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + }; + name = Debug; + }; + 57E301D7C33C28BED6841389AB36D92F /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = AB5F89C2FF338EB3D8A14F31581D0B13 /* TransitionKit-Private.xcconfig */; + buildSettings = { + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_PREFIX_HEADER = "Target Support Files/TransitionKit/TransitionKit-prefix.pch"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = YES; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + }; + name = Debug; + }; + 5CE5176205D06FF3FFE3DDDA9291E44B /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + ONLY_ACTIVE_ARCH = YES; + STRIP_INSTALLED_PRODUCT = NO; + SYMROOT = "${SRCROOT}/../build"; + }; + name = Debug; + }; + 5FDB5D008DD9DAC490D2B00D53A03D87 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = F4846409FD18BF8B96FF09787A484C30 /* AFNetworking-Private.xcconfig */; + buildSettings = { + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_PREFIX_HEADER = "Target Support Files/AFNetworking/AFNetworking-prefix.pch"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = NO; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + }; + name = Release; + }; + 65AF9AB0B82E18AA743FF9676173316B /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = ACAA32E0DD83A1EA3B8803214D102848 /* Pods.release.xcconfig */; + buildSettings = { + ENABLE_STRICT_OBJC_MSGSEND = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = NO; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PODS_ROOT = "$(SRCROOT)"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + }; + name = Release; + }; + 74857149DC1E0D599B8A01A78349A926 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = YES; + ENABLE_NS_ASSERTIONS = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_PREPROCESSOR_DEFINITIONS = "RELEASE=1"; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + STRIP_INSTALLED_PRODUCT = NO; + SYMROOT = "${SRCROOT}/../build"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 9D08367F46BBF5B9140DD3D40AEF7023 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = D11414CAE06B475EA350D0FEC33B4F7D /* RestKit-Private.xcconfig */; + buildSettings = { + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_PREFIX_HEADER = "Target Support Files/RestKit/RestKit-prefix.pch"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = YES; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + }; + name = Debug; + }; + C85D73546CD52F1C1A52C397E1178D3F /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = A8FA5F2052C43B6E4060DAF60265E858 /* SOCKit-Private.xcconfig */; + buildSettings = { + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_PREFIX_HEADER = "Target Support Files/SOCKit/SOCKit-prefix.pch"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = NO; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + }; + name = Release; + }; + CF3A527F185607546641C5490F6977B2 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = A8FA5F2052C43B6E4060DAF60265E858 /* SOCKit-Private.xcconfig */; + buildSettings = { + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_PREFIX_HEADER = "Target Support Files/SOCKit/SOCKit-prefix.pch"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = YES; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + }; + name = Debug; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 18F35DD29D9851E4DF6D21F71EC89D16 /* Build configuration list for PBXNativeTarget "ISO8601DateFormatterValueTransformer" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 53118C6292C556E93925B2081981B36B /* Debug */, + 0AE57E2375439BB6B92C8ACA957B94B9 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 2D8E8EC45A3A1A1D94AE762CB5028504 /* Build configuration list for PBXProject "Pods" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5CE5176205D06FF3FFE3DDDA9291E44B /* Debug */, + 74857149DC1E0D599B8A01A78349A926 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 59A0920A53C9D5A501168E60A7BFECD3 /* Build configuration list for PBXNativeTarget "RKValueTransformers" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 3320DEEF5B3226617E9C30F1A64C7A32 /* Debug */, + 279359901DDD3907B0016EBAFE7F2AE7 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 7CEBC4DE609364610411675E3F25820C /* Build configuration list for PBXNativeTarget "AFNetworking" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 39EE36124B77E37BCF8ADE16B77E7F16 /* Debug */, + 5FDB5D008DD9DAC490D2B00D53A03D87 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 9685A47F63B7FC550A1C98681CED4385 /* Build configuration list for PBXNativeTarget "Pods" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 23B0CABDC81D3EA9DDBC33F608A3E401 /* Debug */, + 65AF9AB0B82E18AA743FF9676173316B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + A765DCCE51BB64312BB4FFF99B73EE53 /* Build configuration list for PBXNativeTarget "RestKit" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 9D08367F46BBF5B9140DD3D40AEF7023 /* Debug */, + 0DFFD5B377646ECA2B3EEEEA5D08A669 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + BE9B407615E85CA189C0133A977CB6E4 /* Build configuration list for PBXNativeTarget "SOCKit" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + CF3A527F185607546641C5490F6977B2 /* Debug */, + C85D73546CD52F1C1A52C397E1178D3F /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + EC5884D823C95D73657B127F496ED2E3 /* Build configuration list for PBXNativeTarget "TransitionKit" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 57E301D7C33C28BED6841389AB36D92F /* Debug */, + 1613D299E6C12EC750981F72447F2D39 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = D41D8CD98F00B204E9800998ECF8427E /* Project object */; +} diff --git a/Pods/RKValueTransformers/Code/RKValueTransformers.h b/Pods/RKValueTransformers/Code/RKValueTransformers.h new file mode 100644 index 0000000..0aa6cee --- /dev/null +++ b/Pods/RKValueTransformers/Code/RKValueTransformers.h @@ -0,0 +1,373 @@ +// +// RKValueTransformers.h +// RestKit +// +// Created by Blake Watters on 8/18/13. +// Copyright (c) 2013 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import + +/** + Objects wish to perform transformation on values as part of a RestKit object mapping operation much adopt the `RKValueTransforming` protocol. Value transformers must introspect a given input value to determine if they are capable of performing a transformation and if so, perform the transformation and assign the new value to the given pointer to an output value and return `YES` or else construct an error describing the failure and return `NO`. Value transformers may also optionally implement a validation method that enables callers to determine if a given value transformer object is capable of performing a transformation on an input value. + */ +@protocol RKValueTransforming + +@required + +/** + Transforms a given value into a new representation. + + Attempts to perform a transformation of a given value into a new representation and returns a Boolean value indicating if the transformation was successful. Transformers are responsible for introspecting their input values before attempting to perform the transformation. If the transformation cannot be performed, then the transformer must construct an `NSError` object describing the nature of the failure else a warning will be emitted. + + @param inputValue The value to be transformed. + @param outputValue A pointer to an `id` object that will be assigned to the transformed representation. May be assigned to `nil` if that is the result of the transformation. + @param outputValueClass The class of the `outputValue` variable. Specifies the expected type of a successful transformation. May be `nil` to indicate that the type is unknown or unimportant. + @param error A pointer to an `NSError` object that must be assigned to a newly constructed `NSError` object if the transformation cannot be performed. + @return A Boolean value indicating if the transformation was successful. This is used to determine whether another transformer should be given an opportunity to attempt a transformation. + */ +- (BOOL)transformValue:(id)inputValue toValue:(id *)outputValue ofClass:(Class)outputValueClass error:(NSError **)error; + +@optional + +/** + Asks the transformer if it is capable of performing a transformation from a given class into a new representation of another given class. + + This is an optional method that need only be implemented by transformers that are tightly bound to values with specific types. + + @param inputValueClass The `Class` of an input value being inspected. + @param outputValueClass The `Class` of an output value being inspected. + @return `YES` if the receiver can perform a transformation between the given source and destination classes. + */ +- (BOOL)validateTransformationFromClass:(Class)inputValueClass toClass:(Class)outputValueClass; + +@end + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/** + The domain for errors emitted by RKValueTransformers + */ +extern NSString *const RKValueTransformersErrorDomain; + +/** + If multiple errors occur in one operation, they are collected in an array and added with this key to the "top-level error" of the operation + */ +extern NSString *const RKValueTransformersDetailedErrorsKey; + +typedef NS_ENUM(NSUInteger, RKValueTransformationError) { + RKValueTransformationErrorUntransformableInputValue = 3000, // The input value was determined to be unacceptable and no transformation was performed. + RKValueTransformationErrorUnsupportedOutputClass = 3001, // The specified class type for the output value is unsupported and no transformation was performed. + RKValueTransformationErrorTransformationFailed = 3002 // A transformation was attempted, but failed. +}; + +/** + Tests if a given input value is of an expected class and returns a failure if it is not. + + This macro is useful for quickly verifying that a transformer can work with a given input value by checking if the value is an instance of an expected class. On failure, the macro constructs an error describing the class mismatch. + + @param inputValue The input value to test. + @param expectedClass The expected class or array of classes of the input value. + @param error A pointer to an `NSError` object in which to assign a newly constructed error if the test fails. Cannot be `nil`. + */ +#define RKValueTransformerTestInputValueIsKindOfClass(inputValue, expectedClass, error) ({ \ + id expectedArgument = (expectedClass); \ + BOOL success = NO; \ + if ([expectedArgument isKindOfClass:[NSArray class]]) { \ + for (Class supportedClass in expectedArgument) {\ + if ([inputValue isKindOfClass:supportedClass]) { \ + success = YES; \ + break; \ + } \ + } \ + } else { \ + success = [inputValue isKindOfClass:expectedArgument]; \ + } \ + if (! success) { \ + if (error) { \ + NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: [NSString stringWithFormat:@"Expected an `inputValue` of type `%@`, but got a `%@`.", expectedArgument, [inputValue class]] };\ + *error = [NSError errorWithDomain:RKValueTransformersErrorDomain code:RKValueTransformationErrorUntransformableInputValue userInfo:userInfo]; \ + } \ + return NO; \ + } \ +}) + +/** + Tests if a given output value class is of an expected class and returns a failure if it is not. + + This macro is useful for quickly verifying that a transformer can work with a given input value by checking if the value is an instance of an expected class. On failure, the macro constructs an error describing the class mismatch. + + @param outputValueClass The input value to test. + @param expectedClass The expected class or array of classes of the input value. + @param error A pointer to an `NSError` object in which to assign a newly constructed error if the test fails. Cannot be `nil`. + */ +#define RKValueTransformerTestOutputValueClassIsSubclassOfClass(outputValueClass, expectedClass, error) ({ \ + BOOL success = NO; \ + id expectedArgument = (expectedClass); \ + if ([expectedArgument isKindOfClass:[NSArray class]]) { \ + for (Class supportedClass in expectedArgument) {\ + if ([outputValueClass isSubclassOfClass:supportedClass]) { \ + success = YES; \ + break; \ + } \ + } \ + } else { \ + success = [outputValueClass isSubclassOfClass:expectedArgument]; \ + } \ + if (! success) { \ + if (error) { \ + NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: [NSString stringWithFormat:@"Expected an `outputValueClass` of type `%@`, but got a `%@`.", expectedArgument, outputValueClass] };\ + *error = [NSError errorWithDomain:RKValueTransformersErrorDomain code:RKValueTransformationErrorUnsupportedOutputClass userInfo:userInfo]; \ + } \ + return NO; \ + } \ +}) + +/** + Tests a condition to evaluate the success of an attempted value transformation and returns a failure if it is not true. + + This macro is useful for quickly verifying that an attempted transformation was successful. If the condition is not true, than an error is constructed describing the failure. + + @param condition The condition to test. + @param expectedClass The expected class of the input value. + @param error A pointer to an `NSError` object in which to assign a newly constructed error if the test fails. Cannot be `nil`. + @param ... A string describing what the failure was that occurred. This may be a format string with additional arguments. + */ +#define RKValueTransformerTestTransformation(condition, error, ...) ({ \ +if (! (condition)) { \ + if (error) { \ + NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: [NSString stringWithFormat:__VA_ARGS__] };\ + *error = [NSError errorWithDomain:RKValueTransformersErrorDomain code:RKValueTransformationErrorTransformationFailed userInfo:userInfo]; \ + } \ + return NO; \ + } \ +}) + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +@class RKCompoundValueTransformer; + +/** + The `RKValueTransformer` class is an abstract base class for implementing a value transformer that conforms to the `RKValueTransforming` protocol. The class is provided to enable third-party extensions of the value transformer to be implemented through subclassing. The default implementation contains no behavior and will raise an exception if an implementation of `transformValue:toValue:ofClass:error:` is not provided by the subclass. `RKValueTransformer` also exposes accessors for the default value transformer implementations that are provided with the library. + */ +@interface RKValueTransformer : NSObject + +///-------------------------------------- +/// @name Retrieving Default Transformers +///-------------------------------------- + +/** + Returns a transformer that will return the input value if it is already of the desired output class. + */ ++ (instancetype)identityValueTransformer; + +/** + Returns a transformer capable of transforming between `NSString` and `NSURL` representations. + */ ++ (instancetype)stringToURLValueTransformer; + +/** + Returns a transformer capable of transforming between `NSNumber` and `NSString` representations. + */ ++ (instancetype)numberToStringValueTransformer; + +/** + Returns a transformer capable of transforming between `NSArray` and `NSOrderedSet` representations. + */ ++ (instancetype)arrayToOrderedSetValueTransformer; + +/** + Returns a transformer capable of transforming between `NSArray` and `NSSet` representations. + */ ++ (instancetype)arrayToSetValueTransformer; + +/** + Returns a transformer capable of transforming between `NSDecimalNumber` and `NSNumber` representations. + */ ++ (instancetype)decimalNumberToNumberValueTransformer; + +/** + Returns a transformer capable of transforming between `NSDecimalNumber` and `NSString` representations. + */ ++ (instancetype)decimalNumberToStringValueTransformer; + +/** + Returns a transformer capable of transforming from `[NSNull null]` to `nil` representations. + */ ++ (instancetype)nullValueTransformer; + +/** + Returns a transformer capable of transforming between objects that conform to the `NSCoding` protocol and `NSData` representations by using an `NSKeyedArchiver`/`NSKeyedUnarchiver` to serialize as a property list. + */ ++ (instancetype)keyedArchivingValueTransformer; + +/** + Returns a transformer capable of transforming between `NSNumber` or `NSString` and `NSDate` representations by evaluating the input value as a time interval since the UNIX epoch (1 January 1970, GMT). + + The transformation treats numeric values as a `double` in order to provide sub-second accuracy. + */ ++ (instancetype)timeIntervalSince1970ToDateValueTransformer; + +/** + Returns a transformer capable of transforming between `NSDate` and `NSString` representations in which the string encodes date and time information in the ISO 8601 timestamp format. + + Note that this transformer is only capable of handling a fully qualified timestamp string rather than the complete ISO 8601 format. For a more complete implementation of the ISO 8601 standard, see the []() project. + */ ++ (instancetype)iso8601TimestampToDateValueTransformer; + +/** + Returns a transformer capable of transforming any `NSObject` that implements the `stringValue` method into an `NSString` representation. + */ ++ (instancetype)stringValueTransformer; + +/** + Returns a transformer capable of enclosing any singular `NSObject` into a collection type such as `NSArray`, `NSSet`, or `NSOrderedSet` (and its mutable descendents). + */ ++ (instancetype)objectToCollectionValueTransformer; + +/** + Returns a transformer capable of transforming any object that conforms to the `NSCopying` protocol into a dictionary representation keyed by the transformed object. + */ ++ (instancetype)keyOfDictionaryValueTransformer; + +/** + Returns a transformer capable of transforming any object conforming to the `NSMutableCopying` protocol into a mutable representation of itself. + */ ++ (instancetype)mutableValueTransformer; + +/** + Returns the singleton instance of the default value transformer. The default transformer is a compound transformer that includes all the individual value transformers implemented on the `RKValueTransformer` base class as well as `NSDateFormatter` instances for the following date format strings: + + * MM/dd/yyyy + * yyyy-MM-dd + + All date formatters are configured to the use `en_US_POSIX` locale and the UTC time zone. + */ ++ (RKCompoundValueTransformer *)defaultValueTransformer; + +/** + Sets the default value transformer to a new instance. Setting the default transformer to `nil` will result in a new singleton instance with the default configuration being rebuilt. + + @param compoundValueTransformer The new default compound transformer. Passing `nil` will reset the transformer to the default configuration. + */ ++ (void)setDefaultValueTransformer:(RKCompoundValueTransformer *)compoundValueTransformer; + +@end + +/** + The `RKBlockValueTransformer` class provides a concrete implementation of the `RKValueTransforming` protocol using blocks to provide the implementation of the transformer. + */ +@interface RKBlockValueTransformer : RKValueTransformer + +///----------------------------------- +/// @name Creating a Block Transformer +///----------------------------------- + +/** + Creates and returns a new value transformer with the given validation and transformation blocks. The blocks are used to provide the implementation of the corresponding methods from the `RKValueTransforming` protocol. + + @param validationBlock A block that evaluates whether the transformer can perform a transformation between a given pair of input and output classes. + */ ++ (instancetype)valueTransformerWithValidationBlock:(BOOL (^)(Class inputValueClass, Class outputValueClass))validationBlock + transformationBlock:(BOOL (^)(id inputValue, id *outputValue, Class outputClass, NSError **error))transformationBlock; + +/** + An optional name for the transformer. + */ +@property (nonatomic, copy) NSString *name; + +@end + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/** + The `RKCompoundValueTransformer` class provides an implementation of the `RKValueTransforming` protocol in which a collection of underlying value transformers are assembled into a composite value transformer. Compound values transformers are ordered collections in which each underlying transformer is given the opportunity to transform a value in the order in which it appears within the receiver. Compound transformers are copyable, enumerable and support subscripted access to the underlying value transformers. + */ +@interface RKCompoundValueTransformer : NSObject + +///-------------------------------------- +/// @name Creating a Compound Transformer +///-------------------------------------- + +/** + Creates and returns a new compound transformer from an array of individual value transformers. + + @param valueTransformers An array containining an arbitrary number of objects that conform to the `RKValueTransforming` protocol. Cannot be `nil`. + @return A new compound transformer initialized with the given collection of underlying transformers. + @raises NSInvalidArgumentException Raised if `valueTransformers` is `nil` or any objects in the given collection do not conform to the `RKValueTransforming` protocol. + */ ++ (instancetype)compoundValueTransformerWithValueTransformers:(NSArray *)valueTransformers; + +///---------------------------------------------------- +/// @name Manipulating the Value Transformer Collection +///---------------------------------------------------- + +/** + Adds the given value transformer to the end of the receiver's transformer collection. + + Adding a transformer appends it to the end of the collection meaning that it will be consulted after all other transformers. + + @param valueTransformer The transformer to add to the receiver. + */ +- (void)addValueTransformer:(id)valueTransformer; + +/** + Removes the given value transformer from the receiver. + + @param valueTransformer The transformer to remove from the receiver. + */ +- (void)removeValueTransformer:(id)valueTransformer; + +/** + Inserts the given value transformer into the receiver at a specific position. If the transformer already exists within the receiver then it is moved to the specified position. + + @param valueTransformer The value transformer to be added to (or moved within) the receiver. + @param index The position at which the transformer should be consulted within the collection. An index of 0 would mean that the transformer is consulted before all other transformers. + */ +- (void)insertValueTransformer:(id)valueTransformer atIndex:(NSUInteger)index; + +/** + Returns a count of the number of value transformers in the receiver. + + @return An integer specifying the number of transformers within the receiver. + */ +- (NSUInteger)numberOfValueTransformers; + +///------------------------------------------ +/// @name Retrieving Constituent Transformers +///------------------------------------------ + +/** + Returns a new array containing a subset of the value transformers contained within the receiver that are valid for a transformation between a representation with a given input class and a given output class. + + Whether or not a given transformer is returned is determined by the invocation of the optional `RKValueTransforming` method `validateTransformationFromClass:toClass:`. Any transformer that does not respond to `validateTransformationFromClass:toClass:` will be included within the returned array. The sequencing of the transformers within the returned array is determined by their position within the receiver. + + If you wish to obtain an array containing all of the transformers contained within the receiver then pass `Nil` for both the `inputValueClass` and `outputValueClass` arguments. + + @param inputValueClass The class of input values that you wish to retrieve the transformers for. Can only be `Nil` if `outputValueClass` is also `Nil`. + @param outputValueClass The class of output values that you wish to retrieve the transformers for. Can only be `Nil` if `inputValueClass` is also `Nil`. + @raises NSInvalidArgumentException Raised if `Nil` is given exclusively for `inputValueClass` or `outputValueClass`. + */ +- (NSArray *)valueTransformersForTransformingFromClass:(Class)inputValueClass toClass:(Class)outputValueClass; + +@end + +// Adopts `RKValueTransforming` to provide transformation from `NSString` <-> `NSNumber` +@interface NSNumberFormatter (RKValueTransformers) +@end + +// Adopts `RKValueTransforming` to provide transformation from `NSString` <-> `NSDate` +@interface NSDateFormatter (RKValueTransformers) +@end diff --git a/Pods/RKValueTransformers/Code/RKValueTransformers.m b/Pods/RKValueTransformers/Code/RKValueTransformers.m new file mode 100644 index 0000000..9211a93 --- /dev/null +++ b/Pods/RKValueTransformers/Code/RKValueTransformers.m @@ -0,0 +1,912 @@ +// +// RKValueTransformers.m +// RestKit +// +// Created by Blake Watters on 8/18/13. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#include +#include +#import "RKValueTransformers.h" + +NSString *const RKValueTransformersErrorDomain = @"org.restkit.RKValueTransformers.ErrorDomain"; +NSString *const RKValueTransformersDetailedErrorsKey = @"detailedErrors"; + +static BOOL RKVTClassIsCollection(Class aClass) +{ + return (aClass && ([aClass isSubclassOfClass:[NSSet class]] || + [aClass isSubclassOfClass:[NSArray class]] || + [aClass isSubclassOfClass:[NSOrderedSet class]])); +} + +@implementation RKValueTransformer + +- (id)init +{ + if ([self class] == [RKValueTransformer class]) { + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:[NSString stringWithFormat:@"`%@` is abstract and cannot be directly instantiated. " + @"Instantiate a subclass implementation instead.", + NSStringFromClass([self class])] + userInfo:nil]; + } + return [super init]; +} + +#pragma mark RKValueTransforming + +- (BOOL)transformValue:(id)inputValue toValue:(__autoreleasing id *)outputValue ofClass:(Class)outputValueClass error:(NSError *__autoreleasing *)error +{ + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:[NSString stringWithFormat:@"`RKValueTransformer` subclasses must provide a concrete implementation of `%@`.", + NSStringFromSelector(_cmd)] + userInfo:nil]; +} + +#pragma mark Default Transformers + ++ (instancetype)singletonValueTransformer:(RKBlockValueTransformer * __strong *)valueTransformer + name:(NSString *)name + onceToken:(dispatch_once_t *)onceToken + validationBlock:(BOOL (^)(Class sourceClass, Class destinationClass))validationBlock + transformationBlock:(BOOL (^)(id inputValue, id *outputValue, Class outputValueClass, NSError **error))transformationBlock +{ + dispatch_once(onceToken, ^{ + RKBlockValueTransformer *transformer = [RKBlockValueTransformer valueTransformerWithValidationBlock:validationBlock transformationBlock:transformationBlock]; + transformer.name = name; + *valueTransformer = transformer; + }); + return *valueTransformer; +} + ++ (instancetype)identityValueTransformer +{ + static dispatch_once_t onceToken; + static RKBlockValueTransformer *valueTransformer; + return [self singletonValueTransformer:&valueTransformer name:NSStringFromSelector(_cmd) onceToken:&onceToken validationBlock:nil transformationBlock:^BOOL(id inputValue, __autoreleasing id *outputValue, __unsafe_unretained Class outputValueClass, NSError *__autoreleasing *error) { + RKValueTransformerTestTransformation([inputValue isKindOfClass:outputValueClass], error, @"The given value is not already an instance of '%@'", outputValueClass); + *outputValue = inputValue; + return YES; + }]; +} + ++ (instancetype)stringToURLValueTransformer +{ + static dispatch_once_t onceToken; + static RKBlockValueTransformer *valueTransformer; + return [self singletonValueTransformer:&valueTransformer name:NSStringFromSelector(_cmd) onceToken:&onceToken validationBlock:^BOOL(__unsafe_unretained Class sourceClass, __unsafe_unretained Class destinationClass) { + return (([sourceClass isSubclassOfClass:[NSString class]] && [destinationClass isSubclassOfClass:[NSURL class]]) || + ([sourceClass isSubclassOfClass:[NSURL class]] && [destinationClass isSubclassOfClass:[NSString class]])); + } transformationBlock:^BOOL(id inputValue, __autoreleasing id *outputValue, Class outputValueClass, NSError *__autoreleasing *error) { + static dispatch_once_t onceToken; + static NSArray *validClasses; + dispatch_once(&onceToken, ^{ + validClasses = @[ [NSString class], [NSURL class]]; + }); + RKValueTransformerTestInputValueIsKindOfClass(inputValue, validClasses, error); + RKValueTransformerTestOutputValueClassIsSubclassOfClass(outputValueClass, validClasses, error); + if ([inputValue isKindOfClass:[NSString class]]) { + NSURL *URL = [NSURL URLWithString:inputValue]; + RKValueTransformerTestTransformation(URL != nil, error, @"Failed transformation of '%@' to URL: the string is malformed and cannot be transformed to an `NSURL` representation.", inputValue); + *outputValue = URL; + } else if ([inputValue isKindOfClass:[NSURL class]]) { + *outputValue = [(NSURL *)inputValue absoluteString]; + } + return YES; + }]; +} + ++ (instancetype)numberToStringValueTransformer +{ + static dispatch_once_t onceToken; + static RKBlockValueTransformer *valueTransformer; + + return [self singletonValueTransformer:&valueTransformer name:NSStringFromSelector(_cmd) onceToken:&onceToken validationBlock:^BOOL(__unsafe_unretained Class sourceClass, __unsafe_unretained Class destinationClass) { + return (([sourceClass isSubclassOfClass:[NSNumber class]] && [destinationClass isSubclassOfClass:[NSString class]]) || + ([sourceClass isSubclassOfClass:[NSString class]] && [destinationClass isSubclassOfClass:[NSNumber class]])); + } transformationBlock:^BOOL(id inputValue, __autoreleasing id *outputValue, Class outputValueClass, NSError *__autoreleasing *error) { + static dispatch_once_t onceToken; + static NSArray *validClasses; + static NSSet *trueStrings; + static NSSet *booleanStrings; + static Class cfBooleanClass1; + static Class cfBooleanClass2; + dispatch_once(&onceToken, ^{ + validClasses = @[ [NSNumber class], [NSString class] ]; + trueStrings = [NSSet setWithObjects:@"true", @"t", @"yes", @"y", nil]; + booleanStrings = [trueStrings setByAddingObjectsFromSet:[NSSet setWithObjects:@"false", @"f", @"no", @"n", nil]]; + cfBooleanClass1 = NSClassFromString(@"__NSCFBoolean"); + cfBooleanClass2 = NSClassFromString(@"NSCFBoolean"); + }); + + RKValueTransformerTestInputValueIsKindOfClass(inputValue, validClasses, error); + RKValueTransformerTestOutputValueClassIsSubclassOfClass(outputValueClass, validClasses, error); + if ([inputValue isKindOfClass:[NSString class]]) { + NSString *lowercasedString = [inputValue lowercaseString]; + if ([booleanStrings containsObject:lowercasedString]) { + // Handle booleans encoded as Strings + *outputValue = [NSNumber numberWithBool:[trueStrings containsObject:lowercasedString]]; + } else if ([lowercasedString rangeOfString:@"." options:NSLiteralSearch].location != NSNotFound) { + // String -> Floating Point Number + // Only use floating point if needed to avoid losing precision on large integers + *outputValue = [NSNumber numberWithDouble:[lowercasedString doubleValue]]; + } else { + // String -> Signed Integer + *outputValue = [NSNumber numberWithLongLong:[lowercasedString longLongValue]]; + } + } else if ([inputValue isKindOfClass:[NSNumber class]]) { + if (cfBooleanClass1 && [inputValue isKindOfClass:cfBooleanClass1]) { + *outputValue = [inputValue boolValue] ? @"true" : @"false"; + } else if (cfBooleanClass2 && [inputValue isKindOfClass:cfBooleanClass2]) { + *outputValue = [inputValue boolValue] ? @"true" : @"false"; + } else { + *outputValue = [inputValue stringValue]; + } + } + return YES; + }]; +} + ++ (instancetype)numberToBooleanValueTransformer { + static dispatch_once_t onceToken; + static RKBlockValueTransformer *valueTransformer; + + static dispatch_once_t booleanClassOnceToken; + static Class cfBooleanClass1; + static Class cfBooleanClass2; + + dispatch_once(&booleanClassOnceToken, ^{ + cfBooleanClass1 = NSClassFromString(@"__NSCFBoolean"); + cfBooleanClass2 = NSClassFromString(@"NSCFBoolean"); + }); + + return [self singletonValueTransformer:&valueTransformer name:NSStringFromSelector(_cmd) onceToken:&onceToken validationBlock:^BOOL(__unsafe_unretained Class sourceClass, __unsafe_unretained Class destinationClass) { + return (([sourceClass isSubclassOfClass:[NSNumber class]] && [destinationClass isSubclassOfClass:[cfBooleanClass1 class]]) || + ([sourceClass isSubclassOfClass:[NSNumber class]] && [destinationClass isSubclassOfClass:[cfBooleanClass2 class]])); + } transformationBlock:^BOOL(id inputValue, __autoreleasing id *outputValue, Class outputValueClass, NSError *__autoreleasing *error) { + + RKValueTransformerTestInputValueIsKindOfClass(inputValue, @[[NSNumber class]], error); + RKValueTransformerTestOutputValueClassIsSubclassOfClass(outputValueClass, @[[NSNumber class]], error); + + *outputValue = inputValue; + + return YES; + }]; +} + ++ (instancetype)arrayToOrderedSetValueTransformer +{ + static dispatch_once_t onceToken; + static RKBlockValueTransformer *valueTransformer; + + return [self singletonValueTransformer:&valueTransformer name:NSStringFromSelector(_cmd) onceToken:&onceToken validationBlock:^BOOL(__unsafe_unretained Class sourceClass, __unsafe_unretained Class destinationClass) { + return (([sourceClass isSubclassOfClass:[NSArray class]] && [destinationClass isSubclassOfClass:[NSOrderedSet class]]) || + ([sourceClass isSubclassOfClass:[NSOrderedSet class]] && [destinationClass isSubclassOfClass:[NSArray class]])); + } transformationBlock:^BOOL(id inputValue, __autoreleasing id *outputValue, Class outputValueClass, NSError *__autoreleasing *error) { + static dispatch_once_t onceToken; + static NSArray *validClasses; + dispatch_once(&onceToken, ^{ + validClasses = @[ [NSArray class], [NSOrderedSet class]]; + }); + RKValueTransformerTestInputValueIsKindOfClass(inputValue, validClasses, error); + RKValueTransformerTestOutputValueClassIsSubclassOfClass(outputValueClass, validClasses, error); + if ([inputValue isKindOfClass:[NSArray class]]) { + *outputValue = [NSOrderedSet orderedSetWithArray:inputValue]; + } else if ([inputValue isKindOfClass:[NSOrderedSet class]]) { + *outputValue = [inputValue array]; + } + return YES; + }]; +} + ++ (instancetype)arrayToSetValueTransformer +{ + static dispatch_once_t onceToken; + static RKBlockValueTransformer *valueTransformer; + + return [self singletonValueTransformer:&valueTransformer name:NSStringFromSelector(_cmd) onceToken:&onceToken validationBlock:^BOOL(__unsafe_unretained Class sourceClass, __unsafe_unretained Class destinationClass) { + return (([sourceClass isSubclassOfClass:[NSArray class]] && [destinationClass isSubclassOfClass:[NSSet class]]) || + ([sourceClass isSubclassOfClass:[NSSet class]] && [destinationClass isSubclassOfClass:[NSArray class]])); + } transformationBlock:^BOOL(id inputValue, __autoreleasing id *outputValue, Class outputValueClass, NSError *__autoreleasing *error) { + static dispatch_once_t onceToken; + static NSArray *validClasses; + dispatch_once(&onceToken, ^{ + validClasses = @[ [NSSet class], [NSArray class]]; + }); + RKValueTransformerTestInputValueIsKindOfClass(inputValue, validClasses, error); + RKValueTransformerTestOutputValueClassIsSubclassOfClass(outputValueClass, validClasses, error); + if ([inputValue isKindOfClass:[NSArray class]]) { + if ([outputValueClass isSubclassOfClass:[NSMutableSet class]]) *outputValue = [NSMutableSet setWithArray:inputValue]; + else *outputValue = [NSSet setWithArray:inputValue]; + } else if ([inputValue isKindOfClass:[NSSet class]]) { + if ([outputValueClass isSubclassOfClass:[NSMutableArray class]]) *outputValue = [[inputValue allObjects] mutableCopy]; + else *outputValue = [inputValue allObjects]; + } + return YES; + }]; +} + ++ (instancetype)decimalNumberToStringValueTransformer +{ + static dispatch_once_t onceToken; + static RKBlockValueTransformer *valueTransformer; + return [self singletonValueTransformer:&valueTransformer name:NSStringFromSelector(_cmd) onceToken:&onceToken validationBlock:^BOOL(__unsafe_unretained Class sourceClass, __unsafe_unretained Class destinationClass) { + return (([sourceClass isSubclassOfClass:[NSDecimalNumber class]] && [destinationClass isSubclassOfClass:[NSString class]]) || + ([sourceClass isSubclassOfClass:[NSString class]] && [destinationClass isSubclassOfClass:[NSDecimalNumber class]])); + } transformationBlock:^BOOL(id inputValue, __autoreleasing id *outputValue, Class outputValueClass, NSError *__autoreleasing *error) { + static dispatch_once_t onceToken; + static NSArray *validClasses; + dispatch_once(&onceToken, ^{ + validClasses = @[ [NSString class], [NSDecimalNumber class]]; + }); + RKValueTransformerTestInputValueIsKindOfClass(inputValue, validClasses, error); + RKValueTransformerTestOutputValueClassIsSubclassOfClass(outputValueClass, validClasses, error); + if ([inputValue isKindOfClass:[NSString class]]) { + NSDecimalNumber *decimalNumber = [NSDecimalNumber decimalNumberWithString:inputValue]; + RKValueTransformerTestTransformation(! [decimalNumber isEqual:[NSDecimalNumber notANumber]], error, @"Failed transformation of '%@' to `NSDecimalNumber`: the input string was transformed into Not a Number (NaN) value.", inputValue); + *outputValue = decimalNumber; + } else if ([inputValue isKindOfClass:[NSDecimalNumber class]]) { + *outputValue = [inputValue stringValue]; + } + return YES; + }]; +} + ++ (instancetype)decimalNumberToNumberValueTransformer +{ + static dispatch_once_t onceToken; + static RKBlockValueTransformer *valueTransformer; + return [self singletonValueTransformer:&valueTransformer name:NSStringFromSelector(_cmd) onceToken:&onceToken validationBlock:^BOOL(__unsafe_unretained Class sourceClass, __unsafe_unretained Class destinationClass) { + return (([sourceClass isSubclassOfClass:[NSDecimalNumber class]] && [destinationClass isSubclassOfClass:[NSNumber class]]) || + ([sourceClass isSubclassOfClass:[NSNumber class]] && [destinationClass isSubclassOfClass:[NSDecimalNumber class]])); + } transformationBlock:^BOOL(id inputValue, __autoreleasing id *outputValue, Class outputValueClass, NSError *__autoreleasing *error) { + static dispatch_once_t onceToken; + static NSArray *validClasses; + dispatch_once(&onceToken, ^{ + validClasses = @[ [NSNumber class], [NSDecimalNumber class]]; + }); + RKValueTransformerTestInputValueIsKindOfClass(inputValue, validClasses, error); + RKValueTransformerTestOutputValueClassIsSubclassOfClass(outputValueClass, validClasses, error); + if ([inputValue isKindOfClass:[NSNumber class]]) { + *outputValue = [NSDecimalNumber decimalNumberWithDecimal:[inputValue decimalValue]]; + } else if ([inputValue isKindOfClass:[NSDecimalNumber class]]) { + *outputValue = inputValue; + } + return YES; + }]; +} + ++ (instancetype)nullValueTransformer +{ + static dispatch_once_t onceToken; + static RKBlockValueTransformer *valueTransformer; + return [self singletonValueTransformer:&valueTransformer name:NSStringFromSelector(_cmd) onceToken:&onceToken validationBlock:nil transformationBlock:^BOOL(id inputValue, __autoreleasing id *outputValue, Class outputValueClass, NSError *__autoreleasing *error) { + RKValueTransformerTestInputValueIsKindOfClass(inputValue, [NSNull class], error); + *outputValue = nil; + return YES; + }]; +} + ++ (instancetype)keyedArchivingValueTransformer +{ + static dispatch_once_t onceToken; + static RKBlockValueTransformer *valueTransformer; + return [self singletonValueTransformer:&valueTransformer name:NSStringFromSelector(_cmd) onceToken:&onceToken validationBlock:^BOOL(__unsafe_unretained Class sourceClass, __unsafe_unretained Class destinationClass) { + return (([destinationClass isSubclassOfClass:[NSData class]] && [sourceClass conformsToProtocol:@protocol(NSCoding)]) || + ([sourceClass isSubclassOfClass:[NSData class]] && [destinationClass conformsToProtocol:@protocol(NSCoding)])); + } transformationBlock:^BOOL(id inputValue, __autoreleasing id *outputValue, Class outputValueClass, NSError *__autoreleasing *error) { + if ([inputValue isKindOfClass:[NSData class]]) { + id unarchivedValue = nil; + @try { + unarchivedValue = [NSKeyedUnarchiver unarchiveObjectWithData:inputValue]; + } + @catch (NSException *exception) { + NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: [NSString stringWithFormat:@"An `%@` exception was encountered while attempting to unarchive the given inputValue.", [exception name]], @"exception": exception }; + if (error) *error = [NSError errorWithDomain:RKValueTransformersErrorDomain code:RKValueTransformationErrorTransformationFailed userInfo:userInfo]; + return NO; + } + if (! [unarchivedValue isKindOfClass:outputValueClass]) { + NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: [NSString stringWithFormat:@"Expected an `outputValueClass` of type `%@`, but the unarchived object is a `%@`.", outputValueClass, [unarchivedValue class]] }; + if (error) *error = [NSError errorWithDomain:RKValueTransformersErrorDomain code:RKValueTransformationErrorTransformationFailed userInfo:userInfo]; + return NO; + } + *outputValue = unarchivedValue; + } else if ([inputValue conformsToProtocol:@protocol(NSCoding)]) { + RKValueTransformerTestOutputValueClassIsSubclassOfClass(outputValueClass, [NSData class], error); + *outputValue = [NSKeyedArchiver archivedDataWithRootObject:inputValue]; + } else { + NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: [NSString stringWithFormat:@"Expected an `inputValue` of type `NSData` or conforming to `NSCoding`, but got a `%@` which does not satisfy these expectation.", [inputValue class]] }; + if (error) *error = [NSError errorWithDomain:RKValueTransformersErrorDomain code:RKValueTransformationErrorUntransformableInputValue userInfo:userInfo]; + return NO; + } + return YES; + }]; +} + ++ (instancetype)timeIntervalSince1970ToDateValueTransformer +{ + static dispatch_once_t onceToken; + static RKBlockValueTransformer *valueTransformer; + return [self singletonValueTransformer:&valueTransformer name:NSStringFromSelector(_cmd) onceToken:&onceToken validationBlock:^BOOL(__unsafe_unretained Class sourceClass, __unsafe_unretained Class destinationClass) { + return ((([sourceClass isSubclassOfClass:[NSString class]] || [sourceClass isSubclassOfClass:[NSNumber class]]) && [destinationClass isSubclassOfClass:[NSDate class]]) || + ([sourceClass isSubclassOfClass:[NSDate class]] && ([destinationClass isSubclassOfClass:[NSNumber class]] || [destinationClass isSubclassOfClass:[NSString class]]))); + } transformationBlock:^BOOL(id inputValue, __autoreleasing id *outputValue, __unsafe_unretained Class outputValueClass, NSError *__autoreleasing *error) { + static dispatch_once_t onceToken; + static NSArray *validClasses; + static NSNumberFormatter *numberFormatter; + dispatch_once(&onceToken, ^{ + validClasses = @[ [NSNumber class], [NSString class], [NSDate class] ]; + numberFormatter = [NSNumberFormatter new]; + numberFormatter.numberStyle = NSNumberFormatterDecimalStyle; + }); + RKValueTransformerTestInputValueIsKindOfClass(inputValue, validClasses, error); + RKValueTransformerTestOutputValueClassIsSubclassOfClass(outputValueClass, validClasses, error); + if ([outputValueClass isSubclassOfClass:[NSDate class]]) { + if ([inputValue isKindOfClass:[NSNumber class]]) { + *outputValue = [NSDate dateWithTimeIntervalSince1970:[inputValue doubleValue]]; + } else if ([inputValue isKindOfClass:[NSString class]]) { + if ([[inputValue stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] length] == 0) { + *outputValue = nil; + return YES; + } + NSString *errorDescription = nil; + NSNumber *formattedNumber; + BOOL success = [numberFormatter getObjectValue:&formattedNumber forString:inputValue errorDescription:&errorDescription]; + RKValueTransformerTestTransformation(success, error, @"%@", errorDescription); + *outputValue = [NSDate dateWithTimeIntervalSince1970:[formattedNumber doubleValue]]; + } + } else if ([outputValueClass isSubclassOfClass:[NSNumber class]]) { + *outputValue = @([inputValue timeIntervalSince1970]); + } else if ([outputValueClass isSubclassOfClass:[NSString class]]) { + *outputValue = [numberFormatter stringForObjectValue:@([inputValue timeIntervalSince1970])]; + } + return YES; + }]; +} + ++ (instancetype)iso8601TimestampToDateValueTransformer +{ + static dispatch_once_t onceToken; + static RKBlockValueTransformer *valueTransformer; + return [self singletonValueTransformer:&valueTransformer name:NSStringFromSelector(_cmd) onceToken:&onceToken validationBlock:^BOOL(__unsafe_unretained Class sourceClass, __unsafe_unretained Class destinationClass) { + return (([sourceClass isSubclassOfClass:[NSString class]] && [destinationClass isSubclassOfClass:[NSDate class]]) || + ([sourceClass isSubclassOfClass:[NSDate class]] && [destinationClass isSubclassOfClass:[NSString class]])); + } transformationBlock:^BOOL(id inputValue, __autoreleasing id *outputValue, __unsafe_unretained Class outputValueClass, NSError *__autoreleasing *error) { + static dispatch_once_t onceToken; + static NSArray *validClasses; + dispatch_once(&onceToken, ^{ + validClasses = @[ [NSString class], [NSDate class] ]; + }); + RKValueTransformerTestInputValueIsKindOfClass(inputValue, validClasses, error); + RKValueTransformerTestOutputValueClassIsSubclassOfClass(outputValueClass, validClasses, error); + if ([outputValueClass isSubclassOfClass:[NSDate class]]) { + static unsigned int const ISO_8601_MAX_LENGTH = 29; + + if ([(NSString *)inputValue length] == 0) { + NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: [NSString stringWithFormat:@"Cannot transform a zero length string"] }; + if (error) *error = [NSError errorWithDomain:RKValueTransformersErrorDomain code:RKValueTransformationErrorUntransformableInputValue userInfo:userInfo]; + return NO; + } + + static NSRegularExpression *validISO8601RegularExpression = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + NSError *error = nil; + static const char * REGEX_ISO8601_TIMESTAMP = + "\\A(\\d{4})-(\\d{2})-(\\d{2})[T\\s](\\d{2}):(\\d{2}):(\\d{2})" // Mandatory - YYYY-MM-DD(T|\s)hh:mm:ss + "(?:" + "[.](\\d{1,6})" // Optional - .nnnnnn + ")?" + "(?:" + "([+-])(\\d{2}):?(\\d{2})|Z" // Optional -[+-]hh:?mm or Z + ")?\\z"; + NSString *regexString = [[NSString alloc] initWithUTF8String:REGEX_ISO8601_TIMESTAMP]; + validISO8601RegularExpression = [NSRegularExpression regularExpressionWithPattern:regexString + options:NSRegularExpressionCaseInsensitive + error:&error]; + + if (! validISO8601RegularExpression) [NSException raise:NSInternalInconsistencyException format:@"The ISO 8601 validation regex failed to parse: %@", error]; + }); + + if (! [validISO8601RegularExpression numberOfMatchesInString:(NSString *)inputValue options:0 range:NSMakeRange(0, [inputValue length])]) { + NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: [NSString stringWithFormat:@"Input value is not a valid ISO 8601 string: '%@'", inputValue] }; + if (error) *error = [NSError errorWithDomain:RKValueTransformersErrorDomain code:RKValueTransformationErrorUntransformableInputValue userInfo:userInfo]; + return NO; + } + + /* Strip milliseconds prior to parsing */ + double milliseconds = 0.f; + if (19 < [inputValue length] && ([inputValue characterAtIndex:19] == '.' || [inputValue characterAtIndex:19] == ':')) { + NSMutableString *newInputString = [NSMutableString stringWithString:[inputValue substringToIndex:19]]; + NSMutableString *millisecondsString = [NSMutableString new]; + + NSUInteger index = 20; + for (; index < [inputValue length]; index++) + { + unichar digit = [inputValue characterAtIndex:index]; + if(digit >= '0' && digit <= '9') + [millisecondsString appendString:[NSString stringWithFormat:@"%C", digit]]; + else + break; + } + + if (index != 20 && index < [inputValue length]) + [newInputString appendString:[inputValue substringFromIndex:index]]; + + inputValue = [NSString stringWithString:newInputString]; + milliseconds = [millisecondsString doubleValue]/1000.f; + } + + const char *constSource = [(NSString *)inputValue cStringUsingEncoding:NSUTF8StringEncoding]; + size_t length = strlen(constSource); + + char source[ISO_8601_MAX_LENGTH]; + memcpy(source, constSource, sizeof (source)); + if (constSource[10] != 'T') + source[10] = 'T'; + + char destination[ISO_8601_MAX_LENGTH]; + if (length == 19) { + memcpy(destination, source, length); + strncpy(destination + length, "+0000\0", 6); + }else if (length == 20 && source[length - 1] == 'Z') { + memcpy(destination, source, length - 1); + strncpy(destination + length - 1, "+0000\0", 6); + } else { + memcpy(destination, source, sizeof (destination)); + if (length == 25 && source[22] == ':') { + destination[22] = destination[23]; + destination[23] = destination[24]; + destination[24] = '\0'; + } + } + + struct tm time = { + .tm_isdst = -1, + }; + + strptime_l(destination, "%FT%T%z", &time, NULL); + + time_t timeIntervalSince1970 = mktime(&time); + RKValueTransformerTestTransformation(timeIntervalSince1970 != -1, error, @"Failed transformation to date representation: time range is beyond the bounds supported by mktime"); + *outputValue = [NSDate dateWithTimeIntervalSince1970:((double)timeIntervalSince1970 + milliseconds)]; + } else if ([outputValueClass isSubclassOfClass:[NSString class]]) { + static NSDateFormatter *iso8601DateFormatter = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + iso8601DateFormatter = [[NSDateFormatter alloc] init]; + [iso8601DateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"]; + [iso8601DateFormatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"UTC"]]; + [iso8601DateFormatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"]]; + }); + *outputValue = [iso8601DateFormatter stringFromDate:(NSDate *)inputValue]; + } + return YES; + }]; +} + ++ (instancetype)stringValueTransformer +{ + static dispatch_once_t onceToken; + static RKBlockValueTransformer *valueTransformer; + return [self singletonValueTransformer:&valueTransformer name:NSStringFromSelector(_cmd) onceToken:&onceToken validationBlock:^BOOL(__unsafe_unretained Class sourceClass, __unsafe_unretained Class destinationClass) { + return ([sourceClass instancesRespondToSelector:@selector(stringValue)] && [destinationClass isSubclassOfClass:[NSString class]]); + } transformationBlock:^BOOL(id inputValue, __autoreleasing id *outputValue, Class outputValueClass, NSError *__autoreleasing *error) { + if (! [inputValue respondsToSelector:@selector(stringValue)]) { + NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: @"Expected an `inputValue` that responds to `stringValue`, but it does not." }; + if (error) *error = [NSError errorWithDomain:RKValueTransformersErrorDomain code:RKValueTransformationErrorUntransformableInputValue userInfo:userInfo]; + return NO; + } + RKValueTransformerTestOutputValueClassIsSubclassOfClass(outputValueClass, [NSString class], error); + *outputValue = [inputValue stringValue]; + return YES; + }]; +} + ++ (instancetype)objectToCollectionValueTransformer +{ + static dispatch_once_t onceToken; + static RKBlockValueTransformer *valueTransformer; + return [self singletonValueTransformer:&valueTransformer name:NSStringFromSelector(_cmd) onceToken:&onceToken validationBlock:^BOOL(__unsafe_unretained Class sourceClass, __unsafe_unretained Class destinationClass) { + return (!RKVTClassIsCollection(sourceClass) && RKVTClassIsCollection(destinationClass)); + } transformationBlock:^BOOL(id inputValue, __autoreleasing id *outputValue, Class outputValueClass, NSError *__autoreleasing *error) { + if (RKVTClassIsCollection([inputValue class])) { + NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: [NSString stringWithFormat:@"Expected an `inputValue` that is not a collection, but got a `%@`.", [inputValue class]] }; + if (error) *error = [NSError errorWithDomain:RKValueTransformersErrorDomain code:RKValueTransformationErrorUntransformableInputValue userInfo:userInfo]; + return NO; + } + static dispatch_once_t onceToken; + static NSArray *validClasses; + dispatch_once(&onceToken, ^{ + validClasses = @[ [NSArray class], [NSSet class], [NSOrderedSet class]]; + }); + RKValueTransformerTestOutputValueClassIsSubclassOfClass(outputValueClass, validClasses, error); + if ([outputValueClass isSubclassOfClass:[NSMutableArray class]]) *outputValue = [NSMutableArray arrayWithObject:inputValue]; + else if ([outputValueClass isSubclassOfClass:[NSMutableSet class]]) *outputValue = [NSMutableSet setWithObject:inputValue]; + else if ([outputValueClass isSubclassOfClass:[NSMutableOrderedSet class]]) *outputValue = [NSMutableOrderedSet orderedSetWithObject:inputValue]; + else if ([outputValueClass isSubclassOfClass:[NSArray class]]) *outputValue = @[ inputValue ]; + else if ([outputValueClass isSubclassOfClass:[NSSet class]]) *outputValue = [NSSet setWithObject:inputValue]; + else if ([outputValueClass isSubclassOfClass:[NSOrderedSet class]]) *outputValue = [NSOrderedSet orderedSetWithObject:inputValue]; + RKValueTransformerTestTransformation(*outputValue, error, @"Failed to transform value into collection %@", outputValueClass); + return YES; + }]; +} + ++ (instancetype)mutableValueTransformer +{ + static dispatch_once_t classesOnceToken; + static NSArray *mutableClasses; + dispatch_once(&classesOnceToken, ^{ + mutableClasses = @[ [NSMutableArray class], [NSMutableDictionary class], [NSMutableString class], [NSMutableSet class], [NSMutableOrderedSet class], [NSMutableData class], [NSMutableIndexSet class], [NSMutableString class], [NSMutableAttributedString class] ]; + }); + + static dispatch_once_t onceToken; + static RKBlockValueTransformer *valueTransformer; + return [self singletonValueTransformer:&valueTransformer name:NSStringFromSelector(_cmd) onceToken:&onceToken validationBlock:^BOOL(__unsafe_unretained Class sourceClass, __unsafe_unretained Class destinationClass) { + /** + NOTE: Because of class clusters in Foundation you cannot make any assumptions about mutability based on classes. For example, given `__NSArrayI` (immutable array) and a destination class of `NSMutableArray`, `isSubClassOfClass:` will not evaluate to `YES`. If you want a mutable result, you need to invoke `mutableCopy`. + */ + return [sourceClass conformsToProtocol:@protocol(NSMutableCopying)] && [mutableClasses containsObject:destinationClass]; + } transformationBlock:^BOOL(id inputValue, __autoreleasing id *outputValue, __unsafe_unretained Class outputValueClass, NSError *__autoreleasing *error) { + if (! [inputValue conformsToProtocol:@protocol(NSMutableCopying)]) { + NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: [NSString stringWithFormat:@"Expected an `inputValue` that conforms to `NSMutableCopying`, but `%@` objects do not.", [inputValue class]] }; + if (error) *error = [NSError errorWithDomain:RKValueTransformersErrorDomain code:RKValueTransformationErrorUntransformableInputValue userInfo:userInfo]; + return NO; + } + RKValueTransformerTestOutputValueClassIsSubclassOfClass(outputValueClass, mutableClasses, error); + *outputValue = [inputValue mutableCopy]; + return YES; + }]; +} + ++ (instancetype)keyOfDictionaryValueTransformer +{ + static dispatch_once_t onceToken; + static RKBlockValueTransformer *valueTransformer; + return [self singletonValueTransformer:&valueTransformer name:NSStringFromSelector(_cmd) onceToken:&onceToken validationBlock:^BOOL(__unsafe_unretained Class sourceClass, __unsafe_unretained Class destinationClass) { + return ([sourceClass conformsToProtocol:@protocol(NSCopying)] && [destinationClass isSubclassOfClass:[NSDictionary class]]); + } transformationBlock:^BOOL(id inputValue, __autoreleasing id *outputValue, Class outputValueClass, NSError *__autoreleasing *error) { + if (! [inputValue conformsToProtocol:@protocol(NSCopying)]) { + NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: @"Expected an `inputValue` that conforms to `NSCopying`, but it does not." }; + if (error) *error = [NSError errorWithDomain:RKValueTransformersErrorDomain code:RKValueTransformationErrorUntransformableInputValue userInfo:userInfo]; + return NO; + } + RKValueTransformerTestOutputValueClassIsSubclassOfClass(outputValueClass, [NSDictionary class], error); + if ([outputValueClass isSubclassOfClass:[NSMutableDictionary class]]) { + *outputValue = [NSMutableDictionary dictionaryWithObject:[NSMutableDictionary dictionary] forKey:inputValue]; + } else { + *outputValue = @{ inputValue: @{} }; + } + + return YES; + }]; +} + +static RKCompoundValueTransformer *RKDefaultValueTransformer; +static dispatch_once_t RKDefaultValueTransformerOnceToken; + ++ (RKCompoundValueTransformer *)defaultValueTransformer +{ + dispatch_once(&RKDefaultValueTransformerOnceToken, ^{ + if (! RKDefaultValueTransformer) { + RKDefaultValueTransformer = [RKCompoundValueTransformer compoundValueTransformerWithValueTransformers:@[ + [self identityValueTransformer], + [self stringToURLValueTransformer], + + // `NSDecimalNumber` transformers must be consulted ahead of `NSNumber` transformers because `NSDecimalNumber` is a subclass thereof + [self decimalNumberToNumberValueTransformer], + [self decimalNumberToStringValueTransformer], + + [self numberToBooleanValueTransformer], + [self numberToStringValueTransformer], + [self arrayToOrderedSetValueTransformer], + [self arrayToSetValueTransformer], + [self nullValueTransformer], + [self keyedArchivingValueTransformer], + [self stringValueTransformer], + [self objectToCollectionValueTransformer], + [self stringValueTransformer], + [self keyOfDictionaryValueTransformer], + [self mutableValueTransformer], + ]]; + + // Default date formatters + [RKDefaultValueTransformer addValueTransformer:[self iso8601TimestampToDateValueTransformer]]; + [RKDefaultValueTransformer addValueTransformer:[self timeIntervalSince1970ToDateValueTransformer]]; + + // The latter three date format strings below represent the three + // date formats specified by the HTTP/1.1 protocol. See + // http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3.1 + // for details + NSArray *defaultDateFormatStrings = @[ + @"MM/dd/yyyy", + @"yyyy-MM-dd", + @"EEE, dd MMM yyyy HH:mm:ss zzz", // RFC 1123 + @"EEEE, dd-MMM-yy HH:mm:ss zzz", // RFC 850 + @"EEE MMM d HH:mm:ss yyyy" // ANSI C asctime() + ]; + for (NSString *dateFormatString in defaultDateFormatStrings) { + NSDateFormatter *dateFormatter = [NSDateFormatter new]; + dateFormatter.dateFormat = dateFormatString; + dateFormatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"]; + dateFormatter.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"UTC"]; + [RKDefaultValueTransformer addValueTransformer:dateFormatter]; + } + } + }); + return RKDefaultValueTransformer; +} + ++ (void)setDefaultValueTransformer:(RKCompoundValueTransformer *)compoundValueTransformer +{ + RKDefaultValueTransformerOnceToken = 0; // resets the once_token so dispatch_once will run again + RKDefaultValueTransformer = compoundValueTransformer; +} + +@end + +@interface RKBlockValueTransformer () +@property (nonatomic, copy) BOOL (^validationBlock)(Class, Class); +@property (nonatomic, copy) BOOL (^transformationBlock)(id, id *, Class, NSError **); +@end + +@implementation RKBlockValueTransformer + ++ (instancetype)valueTransformerWithValidationBlock:(BOOL (^)(Class sourceClass, Class destinationClass))validationBlock + transformationBlock:(BOOL (^)(id inputValue, id *outputValue, Class outputClass, NSError **error))transformationBlock +{ + if (! transformationBlock) [NSException raise:NSInvalidArgumentException format:@"The `transformationBlock` cannot be `nil`."]; + RKBlockValueTransformer *valueTransformer = [self new]; + valueTransformer.validationBlock = validationBlock; + valueTransformer.transformationBlock = transformationBlock; + return valueTransformer; +} + +#pragma mark RKValueTransforming + +- (BOOL)transformValue:(id)inputValue toValue:(__autoreleasing id *)outputValue ofClass:(Class)outputValueClass error:(NSError *__autoreleasing *)error +{ + NSError *blockError = nil; + BOOL success = self.transformationBlock(inputValue, outputValue, outputValueClass, &blockError); + if (error) *error = blockError; + return success; +} + +- (BOOL)validateTransformationFromClass:(Class)sourceClass toClass:(Class)destinationClass +{ + if (self.validationBlock) return self.validationBlock(sourceClass, destinationClass); + else return YES; +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@"<%@: %p, name: %@>", NSStringFromClass([self class]), self, self.name]; +} + +@end + +@interface RKCompoundValueTransformer () +@property (nonatomic, strong) NSMutableArray *valueTransformers; +@property (nonatomic, strong) NSMutableDictionary *transformerCache; +@property (nonatomic) dispatch_queue_t cacheQueue; +@end + +@implementation RKCompoundValueTransformer + ++ (instancetype)compoundValueTransformerWithValueTransformers:(NSArray *)valueTransformers +{ + if (! valueTransformers) [NSException raise:NSInvalidArgumentException format:@"`valueTransformers` argument cannot be `nil`."]; + for (id valueTransformer in valueTransformers) { + if (! [valueTransformer conformsToProtocol:@protocol(RKValueTransforming)]) { + [NSException raise:NSInvalidArgumentException format:@"All objects in the given `valueTransformers` collection must conform to the `RKValueTransforming` protocol."]; + } + } + RKCompoundValueTransformer *valueTransformer = [self new]; + valueTransformer.valueTransformers = [valueTransformers mutableCopy]; + return valueTransformer; +} + +- (id)init +{ + self = [super init]; + if (self) { + self.valueTransformers = [NSMutableArray new]; + self.transformerCache = [NSMutableDictionary new]; + self.cacheQueue = dispatch_queue_create("org.restkit.value-transformer.compound-cache", DISPATCH_QUEUE_CONCURRENT); + } + return self; +} + +- (void)dealloc +{ +#if !OS_OBJECT_USE_OBJC + if (_cacheQueue) dispatch_release(_cacheQueue); +#endif + _cacheQueue = NULL; +} + +- (void)invalidateCache +{ + dispatch_barrier_sync(self.cacheQueue, ^{ + [self.transformerCache removeAllObjects]; + }); +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@"<%@: %p, valueTransformers=%@>", NSStringFromClass([self class]), self, self.valueTransformers]; +} + +- (void)addValueTransformer:(id)valueTransformer +{ + if (! valueTransformer) [NSException raise:NSInvalidArgumentException format:@"Cannot add `nil` to a compound transformer."]; + [self.valueTransformers addObject:valueTransformer]; + [self invalidateCache]; +} + +- (void)removeValueTransformer:(id)valueTransformer +{ + if (! valueTransformer) [NSException raise:NSInvalidArgumentException format:@"Cannot remove `nil` from a compound transformer."]; + [self.valueTransformers removeObject:valueTransformer]; + [self invalidateCache]; +} + +- (void)insertValueTransformer:(id)valueTransformer atIndex:(NSUInteger)index +{ + if (! valueTransformer) [NSException raise:NSInvalidArgumentException format:@"Cannot insert `nil` into a compound transformer."]; + [self removeValueTransformer:valueTransformer]; + [self.valueTransformers insertObject:valueTransformer atIndex:index]; +} + +- (NSUInteger)numberOfValueTransformers +{ + return [self.valueTransformers count]; +} + +- (NSArray *)valueTransformersForTransformingFromClass:(Class)sourceClass toClass:(Class)destinationClass +{ + if (sourceClass == Nil && destinationClass == Nil) return [self.valueTransformers copy]; + else if (sourceClass == Nil || destinationClass == Nil) [NSException raise:NSInvalidArgumentException format:@"If you specify a source or destination class then you must specify both."]; + + /* See if we have cached values */ + __block NSArray *transformers; + dispatch_sync(self.cacheQueue, ^{ + transformers = [[[self transformerCache] objectForKey:(id)sourceClass] objectForKey:(id)destinationClass]; + }); + + if (transformers != nil) return transformers; + + NSMutableArray *matchingTransformers = [[NSMutableArray alloc] initWithCapacity:[self.valueTransformers count]]; + for (RKValueTransformer *valueTransformer in self) { + if (! [valueTransformer respondsToSelector:@selector(validateTransformationFromClass:toClass:)] + || [valueTransformer validateTransformationFromClass:sourceClass toClass:destinationClass]) { + [matchingTransformers addObject:valueTransformer]; + } + } + + transformers = [matchingTransformers copy]; + dispatch_barrier_sync(self.cacheQueue, ^{ + NSMutableDictionary *cache = self.transformerCache; + NSMutableDictionary *sourceDict = [cache objectForKey:sourceClass]; + if (sourceDict == nil) + { + sourceDict = [NSMutableDictionary new]; + [cache setObject:sourceDict forKey:(id)sourceClass]; + } + + [sourceDict setObject:transformers forKey:(id)destinationClass]; + }); + + return transformers; +} + +- (id)objectAtIndexedSubscript:(NSUInteger)index +{ + return [self.valueTransformers objectAtIndex:index]; +} + +#pragma mark RKValueTransforming + +- (BOOL)transformValue:(id)inputValue toValue:(__autoreleasing id *)outputValue ofClass:(__unsafe_unretained Class)outputValueClass error:(NSError *__autoreleasing *)error +{ + NSArray *matchingTransformers = [self valueTransformersForTransformingFromClass:[inputValue class] toClass:outputValueClass]; + NSMutableArray *errors; + NSError *underlyingError = nil; + for (id valueTransformer in matchingTransformers) { + BOOL success = [valueTransformer transformValue:inputValue toValue:outputValue ofClass:outputValueClass error:&underlyingError]; + if (success) return YES; + if (errors == nil) errors = [NSMutableArray new]; + [errors addObject:underlyingError]; + } + + if (errors.count > 0) { + errors = errors ?: (id)[NSArray new]; + NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: [NSString stringWithFormat:@"Failed transformation of value '%@' to %@: none of the %lu value transformers consulted were successful.", inputValue, outputValueClass, (unsigned long)[matchingTransformers count]], RKValueTransformersDetailedErrorsKey: errors }; + *error = [NSError errorWithDomain:RKValueTransformersErrorDomain code:RKValueTransformationErrorTransformationFailed userInfo:userInfo]; + } + return NO; +} + +- (BOOL)validateTransformationFromClass:(Class)sourceClass toClass:(Class)destinationClass +{ + return [[self valueTransformersForTransformingFromClass:sourceClass toClass:destinationClass] count] > 0; +} + +#pragma mark NSCopying + +- (id)copyWithZone:(NSZone *)zone +{ + RKCompoundValueTransformer *compoundValueTransformer = [[[self class] allocWithZone:zone] init]; + compoundValueTransformer.valueTransformers = [self.valueTransformers mutableCopy]; + return compoundValueTransformer; +} + +#pragma mark NSFastEnumeration + +- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id __unsafe_unretained [])buffer count:(NSUInteger)len +{ + return [self.valueTransformers countByEnumeratingWithState:state objects:buffer count:len]; +} + +@end + +@implementation NSNumberFormatter (RKValueTransformers) + +- (BOOL)validateTransformationFromClass:(Class)inputValueClass toClass:(Class)outputValueClass +{ + return (([inputValueClass isSubclassOfClass:[NSNumber class]] && [outputValueClass isSubclassOfClass:[NSString class]]) || + ([inputValueClass isSubclassOfClass:[NSString class]] && [outputValueClass isSubclassOfClass:[NSNumber class]])); +} + +- (BOOL)transformValue:(id)inputValue toValue:(id *)outputValue ofClass:(Class)outputValueClass error:(NSError **)error +{ + RKValueTransformerTestInputValueIsKindOfClass(inputValue, (@[ [NSString class], [NSNumber class] ]), error); + RKValueTransformerTestOutputValueClassIsSubclassOfClass(outputValueClass, (@[ [NSString class], [NSNumber class] ]), error); + if ([inputValue isKindOfClass:[NSString class]]) { + NSString *errorDescription = nil; + BOOL success = [self getObjectValue:outputValue forString:inputValue errorDescription:&errorDescription]; + RKValueTransformerTestTransformation(success, error, @"%@", errorDescription); + } else if ([inputValue isKindOfClass:[NSNumber class]]) { + *outputValue = [self stringFromNumber:inputValue]; + } + return YES; +} + +@end + +@implementation NSDateFormatter (RKValueTransformers) + +- (BOOL)validateTransformationFromClass:(Class)inputValueClass toClass:(Class)outputValueClass +{ + return (([inputValueClass isSubclassOfClass:[NSDate class]] && [outputValueClass isSubclassOfClass:[NSString class]]) || + ([inputValueClass isSubclassOfClass:[NSString class]] && [outputValueClass isSubclassOfClass:[NSDate class]])); +} + +- (BOOL)transformValue:(id)inputValue toValue:(id *)outputValue ofClass:(Class)outputValueClass error:(NSError **)error +{ + RKValueTransformerTestInputValueIsKindOfClass(inputValue, (@[ [NSString class], [NSDate class] ]), error); + RKValueTransformerTestOutputValueClassIsSubclassOfClass(outputValueClass, (@[ [NSString class], [NSDate class] ]), error); + if ([inputValue isKindOfClass:[NSString class]]) { + NSString *errorDescription = nil; + BOOL success = [self getObjectValue:outputValue forString:inputValue errorDescription:&errorDescription]; + RKValueTransformerTestTransformation(success, error, @"%@", errorDescription); + } else if ([inputValue isKindOfClass:[NSDate class]]) { + *outputValue = [self stringFromDate:inputValue]; + } + return YES; +} + +@end diff --git a/Pods/RKValueTransformers/LICENSE b/Pods/RKValueTransformers/LICENSE new file mode 100644 index 0000000..37ec93a --- /dev/null +++ b/Pods/RKValueTransformers/LICENSE @@ -0,0 +1,191 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright +owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, "control" means (i) the power, direct or +indirect, to cause the direction or management of such entity, whether by +contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising +permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including +but not limited to software source code, documentation source, and configuration +files. + +"Object" form shall mean any form resulting from mechanical transformation or +translation of a Source form, including but not limited to compiled object code, +generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made +available under the License, as indicated by a copyright notice that is included +in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that +is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative Works +shall not include works that remain separable from, or merely link (or bind by +name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version +of the Work and any modifications or additions to that Work or Derivative Works +thereof, that is intentionally submitted to Licensor for inclusion in the Work +by the copyright owner or by an individual or Legal Entity authorized to submit +on behalf of the copyright owner. For the purposes of this definition, +"submitted" means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and +issue tracking systems that are managed by, or on behalf of, the Licensor for +the purpose of discussing and improving the Work, but excluding communication +that is conspicuously marked or otherwise designated in writing by the copyright +owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the Work and such +Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where +such license applies only to those patent claims licensable by such Contributor +that are necessarily infringed by their Contribution(s) alone or by combination +of their Contribution(s) with the Work to which such Contribution(s) was +submitted. If You institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work or a +Contribution incorporated within the Work constitutes direct or contributory +patent infringement, then any patent licenses granted to You under this License +for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof +in any medium, with or without modifications, and in Source or Object form, +provided that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of +this License; and +You must cause any modified files to carry prominent notices stating that You +changed the files; and +You must retain, in the Source form of any Derivative Works that You distribute, +all copyright, patent, trademark, and attribution notices from the Source form +of the Work, excluding those notices that do not pertain to any part of the +Derivative Works; and +If the Work includes a "NOTICE" text file as part of its distribution, then any +Derivative Works that You distribute must include a readable copy of the +attribution notices contained within such NOTICE file, excluding those notices +that do not pertain to any part of the Derivative Works, in at least one of the +following places: within a NOTICE text file distributed as part of the +Derivative Works; within the Source form or documentation, if provided along +with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents of +the NOTICE file are for informational purposes only and do not modify the +License. You may add Your own attribution notices within Derivative Works that +You distribute, alongside or as an addendum to the NOTICE text from the Work, +provided that such additional attribution notices cannot be construed as +modifying the License. +You may add Your own copyright statement to Your modifications and may provide +additional or different license terms and conditions for use, reproduction, or +distribution of Your modifications, or for any such Derivative Works as a whole, +provided Your use, reproduction, and distribution of the Work otherwise complies +with the conditions stated in this License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted +for inclusion in the Work by You to the Licensor shall be under the terms and +conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of +any separate license agreement you may have executed with Licensor regarding +such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides the +Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, +including, without limitation, any warranties or conditions of TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are +solely responsible for determining the appropriateness of using or +redistributing the Work and assume any risks associated with Your exercise of +permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), +contract, or otherwise, unless required by applicable law (such as deliberate +and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, incidental, +or consequential damages of any character arising as a result of this License or +out of the use or inability to use the Work (including but not limited to +damages for loss of goodwill, work stoppage, computer failure or malfunction, or +any and all other commercial damages or losses), even if such Contributor has +been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to +offer, and charge a fee for, acceptance of support, warranty, indemnity, or +other liability obligations and/or rights consistent with this License. However, +in accepting such obligations, You may act only on Your own behalf and on Your +sole responsibility, not on behalf of any other Contributor, and only if You +agree to indemnify, defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason of your +accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work + +To apply the Apache License to your work, attach the following boilerplate +notice, with the fields enclosed by brackets "[]" replaced with your own +identifying information. (Don't include the brackets!) The text should be +enclosed in the appropriate comment syntax for the file format. We also +recommend that a file or class name and description of purpose be included on +the same "printed page" as the copyright notice for easier identification within +third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Pods/RKValueTransformers/README.md b/Pods/RKValueTransformers/README.md new file mode 100644 index 0000000..0480db0 --- /dev/null +++ b/Pods/RKValueTransformers/README.md @@ -0,0 +1,209 @@ +RKValueTransformers +=================== + +[![Build Status](http://img.shields.io/travis/RestKit/RKValueTransformers/master.svg?style=flat)](https://travis-ci.org/RestKit/RKValueTransformers) +![Pod Version](http://cocoapod-badges.herokuapp.com/v/RKValueTransformers/badge.png) +![Pod Platform](http://cocoapod-badges.herokuapp.com/p/RKValueTransformers/badge.png) + +**A simple, powerful Objective-C value transformation API extracted from RestKit** + +RKValueTransformers is a standalone library that provides a simple value transformation API in Objective-C. Value transformation is the process of converting a value between representations and is a core part of any system that requires that data be transmitted and received in a serialization format distinct from the local data model. + +In the general context of a RESTful API this means the transformation between values encoded in an XML or JSON document and local attributes of your data model. The most familiar and obvious example is the transformation of date and time data encoded as a string in a JSON document and represented locally as an `NSDate` attribute of an `NSObject` or `NSManagedObject` derived class. RKValueTransformers provides a simple, well-designed API for generalizing and simplifying the task of handling an arbitrarily complex set of value transformation requirements for your iOS or Mac OS X application. + +Value transformation is a core feature of [RestKit](http://github.com/RestKit/RestKit) and RKValueTransformers was extracted from the parent project to benefit the larger Cocoa development community. If you are looking for a comprehensive solution for your RESTful API needs then be sure to give RestKit a closer look. + +### Features + +RKValueTransformers is a "batteries included" library that ships with value transformers handling the most common transformations. The core set of transformers can be customized and new transformers are easily implemented to meet the needs of any application. + +* Includes a rich set of transformers covering the most common transformations: + * `NSString` <-> `NSURL` + * `NSNumber` <-> `NSString` + * `NSArray` <-> `NSOrderedSet` + * `NSArray` <-> `NSSet` + * `NSDecimalNumber` <-> `NSNumber` + * `NSDecimalNumber` <-> `NSString` + * `NSNull` <-> `nil` + * Any class conforming to `NSCoding` <-> `NSData` + * UNIX Time Interval encoded as `NSNumber` or `NSString` <-> `NSDate` + * ISO 8601 Timestamp strings <-> `NSDate` (Only supports complete timestamp strings. On 32 bit systems such as iOS devices pre-iPhone 5s only years < 2038 are supported) + * Any object implementing `stringValue` -> `NSString` + * Any singular object to a collection (`NSArray`, `NSSet`, `NSOrderedSet` and their mutable counterparts) + * Any object and an `NSDictionary` (object becomes a key for empty nested dictionary) + * Any class conforming to `NSMutableCoding` -> mutable representation of itself + * `NSString` <-> `NSDate` via `NSDateFormatter`. Default formats include: + * RFC 1123 format + * RFC 850 format + * ANSI C's asctime() format + * `NSString` <-> `NSNumber` via `NSNumberFormatter` +* Lightweight. Implemented in a single pair or header and implementation files. +* Fully unit tested and documented. +* Extensible by implementing the `RKValueTransforming` protocol, subclassing `RKValueTransformer` or with blocks via `RKBlockValueTransformer`. +* Multiple value transformers can be assembled into a composite transformer via the `RKCompoundValueTransformer` class. +* Transparently improves date transformation performance by providing a cache of date formatters. +* Fully integrated with RestKit. + +## Examples + +All value transformation is performed via an abstract common interface defined by the `RKValueTransforming` protocol: + +```objc +NSString *stringContainingDecimalNumber = @"3.4593895835"; +NSError *error = nil; +NSDecimalNumber *decimalNumber = nil; +BOOL success = [[RKValueTransformers decimalNumberToStringValueTransformer] transformValue:stringContainingDecimalNumber toValue:&decimalNumber ofClass:[NSDecimalNumber class] error:&error]; +``` + +The `transformValue:toValue:ofClass:error:` method is always the same regardless of the implementation details of the underlying transformation. It is guaranteed to always return a Boolean value indicating if the transformation was successful and value transformers **must** return an `NSError` in the event the transformation could not be performed. + +### Validating a Transformation + +In many cases, whether or not a given transformation can be performed can be determined entirely by the types involved in the transformation. In these cases, a value transformer may implement the optional `RKValueTransforming` method `validateTransformationFromClass:(Class)inputValueClass toClass:(Class)outputValueClass`: + +```objc +BOOL isTransformationPossible = [[RKValueTransformers arrayToSetValueTransformer] validateTransformationFromClass:[NSSet class] toClass:[NSArray class]]; +NSAssert(isTransformationPossible == YES, @"Should be `YES`"); +isTransformationPossible = [[RKValueTransformers arrayToSetValueTransformer] validateTransformationFromClass:[NSSet class] toClass:[NSData class]]; +NSAssert(isTransformationPossible == NO, @"Should be `NO`"); +``` + +Note that as this is an optional method you must check that a given instance responds to the validation selector. If it does not then the transformation cannot be validated and a transformation must be attempted to determine success or failure. + +### Compound Transformers + +Individual transformers are very convenient -- they abstract away the need to remember how to implement a given transformation and present a simple interface for transformations. But the real power of RKValueTransformers emerges when you assemble a collection of value transformers into a compound transformer via the `RKCompoundValueTransformer` class. Compound value transformers also implement the `RKValueTransforming` protocol -- but instead of providing any value transformation and validation themselves they proxy the calls to a collection of underlying value transformers in programmer defined order. This allows you to configure a set of transformers in a specific order such that the first transformer that is capable of performing a given transformation will handle it. + +Consider for example that a given application may interact with several API's that return dates as strings in several different formats. We wish to be able to transform any given string value into an `NSDate` without worrying about the details. We could configure a compound transformer to handle this task like so: + +```objc +NSArray *dateFormats = @[ @"MM/dd/yyyy", @"yyyy-MM-dd'T'HH:mm:ss'Z'", @"yyyy-MM-dd" ]; +RKCompoundValueTransformer *compoundValueTransformer = [RKCompoundValueTransformer new]; +for (NSString *dateFormat in dateFormats) { + NSDateFormatter *dateFormatter = [NSDateFormatter new]; + dateFormatter.dateFormat = dateFormat; + [compoundValueTransformer addValueTransformer:dateFormatter]; +} + +[compoundValueTransformer addValueTransformer:[RKValueTransformer timeIntervalSince1970ToDateValueTransformer]]; + +NSArray *dateStrings = @[ @"11/27/1982", @"1378767519.18176508", @"2013-11-27", @"2013-04-23T16:29:05Z" ]; +NSError *error = nil; +for (NSString *dateString in dateStrings) { + NSDate *date = nil; + BOOL success = [compoundValueTransformer transformValue:dateString toValue:&date ofClass:[NSDate class]]; + NSLog(@"Transformed value '%@' to value '%@' successfully=%@, error=%@", dateString, date, success ? @"YES" : @"NO", error); +} +``` + +### Block Value Transformers + +RKValueTransformers supports the creation of ad-hoc value transformer instances implemented via blocks. For example, one could implement a value transformer that turns all `NSString` instances into uppercase strings like so: + +```objc +RKValueTransformer *uppercaseStringTransformer = [RKBlockValueTransformer valueTransformerWithValidationBlock:^BOOL(__unsafe_unretained Class sourceClass, __unsafe_unretained Class destinationClass) { + // We transform a `NSString` into another `NSString` + return ([sourceClass isSubclassOfClass:[NSString class]] && [destinationClass isSubclassOfClass:[NSString class]]); +} transformationBlock:^BOOL(id inputValue, __autoreleasing id *outputValue, Class outputValueClass, NSError *__autoreleasing *error) { + // Validate the input and output + RKValueTransformerTestInputValueIsKindOfClass(inputValue, [NSString class], error); + RKValueTransformerTestOutputValueClassIsSubclassOfClass(outputValueClass, [NSString class], error); + + // Perform the transformation + *outputValue = [(NSString *)inputValue uppercaseString]; + return YES; +}]; +``` + +## Installation + +RKValueTransformers is extremely lightweight and has no direct dependencies outside of the Cocoa Foundation framework. As such, the library can be trivially be installed into any Cocoa project by directly adding the source code. Despite this fact, we recommend installing via CocoaPods as it provides modularity and enables the easy installation of new value transformers that are dependent on RKValueTransformers itself. + +### Via CocoaPods + +The recommended approach for installing RKValueTransformers is via the [CocoaPods](http://cocoapods.org/) package manager, as it provides flexible dependency management and dead simple installation. For best results, it is recommended that you install via CocoaPods **>= 0.24.0** using Git **>= 1.8.0** installed via Homebrew. + +Install CocoaPods if not already available: + +``` bash +$ [sudo] gem install cocoapods +$ pod setup +``` + +Change to the directory of your Xcode project, and Create and Edit your Podfile and add RKValueTransformers: + +``` bash +$ cd /path/to/MyProject +$ touch Podfile +$ edit Podfile +platform :ios, '5.0' +# Or platform :osx, '10.7' +pod 'RKValueTransformers', '~> 1.0.0' +``` + +Install into your project: + +``` bash +$ pod install +``` + +Open your project in Xcode from the .xcworkspace file (not the usual project file) + +``` bash +$ open MyProject.xcworkspace +``` + +### Via Source Code + +Simply add `RKValueTransformers.h` and `RKValueTransformers.m` to your project and `#import "RKValueTransformers.h"`. + +## Design & Implementation Details + +RKValueTransformers is designed to be simple to integrate and use. The entire library consists of a single protocol, three classes, and a handful of category implementations: + +* `RKValueTransforming` - Defines the value transformation API. Adopted by any class that wishes to act as a value transformer. +* `RKValueTransformer` - An abstract base class that implements `RKValueTransforming`. The base class includes static accessors for retrieving singleton instances of the bundled value transformers. Extension libraries can subclass `RKValueTransformer` to provide new transformers. +* `RKBlockValueTransformer` - A concrete subclass of `RKValueTransformer` that enables the creation of ad-hoc value transformers defined via blocks. +* `RKCompoundValueTransformer` - A concrete implementation of `RKValueTransforming` that proxies calls to an underlying collection of value transformers and provides support for composing value transformers. + +For those implementing value transformers, a few macros are included to simplify the implementation of validation and transformation methods: + +* `RKValueTransformerTestInputValueIsKindOfClass` - Tests that a given input value is an instance of a given class or one of its subclasses. If the test evaluates negatively, then `NO` is returned and an appropriate `NSError` is emitted. +* `RKValueTransformerTestOutputValueClassIsSubclassOfClass` - Tests that a given output value class is equal to a given class or is a subclass there of. If the test evaluates negatively, then `NO` is returned an appropriate `NSError` is emitted. +* `RKValueTransformerTestTransformation` - Tests that a given transformation was successful. If the test evaluates negatively, then `NO` is returned an appropriate `NSError` is emitted. + +### Why not NSValueTransformer? + +In developing RKValueTransformers we looked closely at `NSValueTransformer` and ultimately determined that it was not a great fit for our needs. Specifically we found the following issues: + +1. `NSValueTransformer` defines a notion of 'forward' and 'reverse' transformation that doesn't map cleanly in a system primarilly concerned with type transformations. Which side do you consider forward? This gets worse when you consider transformations that can occur between more than just two types. +2. `NSValueTransformer` exposes the class of the "output" object via the class method `transformedValueClass`. This becomes annoying as you are forced to use inheritance to express type knowledge. This necessitates directly inheriting from `NSValueTransformer` or using fancy run-time hackery such as that [utilized by TransformerKit](https://github.com/mattt/TransformerKit/blob/master/TransformerKit/NSValueTransformer%2BTransformerKit.m). +3. `NSValueTransformer` exposes a single global name based registry for value transformers via the `setValueTransformer:forName:` and `valueTransformerForName:` methods. Ultimately this is not granular enough to provide necessary flexibility and requires the use of names (as opposed to type information) to look up transformers. + +Given all of the above it just made sense to go back to a clean slate and design a solution to the value transformation problem from scratch. + +## Unit Tests + +RKValueTransformers is tested using the [Expecta](https://github.com/specta/Expecta) library of unit testing matchers. In order to run the tests, you must do the following: + +1. Install the dependencies via CocoaPods: `pod install` +1. Open the workspace: `open RKValueTransformers.xcworkspace` +1. Run the specs via the **Product** menu > **Test** + +## Credits + +Blake Watters + +- http://github.com/blakewatters +- http://twitter.com/blakewatters +- blakewatters@gmail.com + +Samuel E. Giddins + +- https://github.com/segiddins +- http://twitter.com/segiddins +- segiddins@segiddins.me + +## License + +RKValueTransformers is available under the Apache 2 License. See the LICENSE file for more info. diff --git a/Pods/RestKit/Code/CoreData.h b/Pods/RestKit/Code/CoreData.h new file mode 100644 index 0000000..ff8972d --- /dev/null +++ b/Pods/RestKit/Code/CoreData.h @@ -0,0 +1,33 @@ +// +// CoreData.h +// RestKit +// +// Created by Blake Watters on 9/30/10. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import +#import "ObjectMapping.h" +#import "RKManagedObjectStore.h" +#import "RKManagedObjectImporter.h" +#import "RKManagedObjectMappingOperationDataSource.h" +#import "RKEntityMapping.h" +#import "RKManagedObjectCaching.h" +#import "RKInMemoryManagedObjectCache.h" +#import "RKFetchRequestManagedObjectCache.h" + +#import "RKPropertyInspector+CoreData.h" +#import "NSManagedObjectContext+RKAdditions.h" +#import "NSManagedObject+RKAdditions.h" diff --git a/Pods/RestKit/Code/CoreData/NSManagedObject+RKAdditions.h b/Pods/RestKit/Code/CoreData/NSManagedObject+RKAdditions.h new file mode 100644 index 0000000..5fae1b1 --- /dev/null +++ b/Pods/RestKit/Code/CoreData/NSManagedObject+RKAdditions.h @@ -0,0 +1,38 @@ +// +// NSManagedObject+RKAdditions.h +// RestKit +// +// Created by Blake Watters on 3/14/12. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// + +#import + +@class RKManagedObjectStore, RKEntityMapping; + +/** + Provides extensions to NSManagedObject for various common tasks. + */ +@interface NSManagedObject (RKAdditions) + +///-------------------------------------- +/// @name Inspecting Managed Object State +///-------------------------------------- + +/** + Determines if the receiver has been deleted from the persistent store + and removed from the object graph. + + Unlike isDeleted, will return YES after a save event or if the managed object was deleted + in another managed object context that was then merged to the persistent store. + + @return YES if the object has been deleted from the persistent store, else NO. + */ +@property (nonatomic, readonly) BOOL hasBeenDeleted; + +/** + * Returns YES when an object has not been saved to the managed object context yet + */ +@property (nonatomic, readonly) BOOL isNew; + +@end diff --git a/Pods/RestKit/Code/CoreData/NSManagedObject+RKAdditions.m b/Pods/RestKit/Code/CoreData/NSManagedObject+RKAdditions.m new file mode 100644 index 0000000..196ff18 --- /dev/null +++ b/Pods/RestKit/Code/CoreData/NSManagedObject+RKAdditions.m @@ -0,0 +1,28 @@ +// +// NSManagedObject+RKAdditions.m +// RestKit +// +// Created by Blake Watters on 3/14/12. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// + +#import "NSManagedObject+RKAdditions.h" +#import "NSManagedObjectContext+RKAdditions.h" +#import "RKLog.h" +#import "RKManagedObjectStore.h" + +@implementation NSManagedObject (RKAdditions) + +- (BOOL)hasBeenDeleted +{ + NSManagedObject *managedObjectClone = [[self managedObjectContext] existingObjectWithID:[self objectID] error:nil]; + return (managedObjectClone == nil) ? YES : NO; +} + +- (BOOL)isNew +{ + NSDictionary *vals = [self committedValuesForKeys:nil]; + return [vals count] == 0; +} + +@end diff --git a/Pods/RestKit/Code/CoreData/NSManagedObjectContext+RKAdditions.h b/Pods/RestKit/Code/CoreData/NSManagedObjectContext+RKAdditions.h new file mode 100644 index 0000000..cdf773d --- /dev/null +++ b/Pods/RestKit/Code/CoreData/NSManagedObjectContext+RKAdditions.h @@ -0,0 +1,79 @@ +// +// NSManagedObjectContext+RKAdditions.h +// RestKit +// +// Created by Blake Watters on 3/14/12. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import + +@class RKManagedObjectStore; + +/** + Provides extensions to `NSManagedObjectContext` for various common tasks. + */ +@interface NSManagedObjectContext (RKAdditions) + +///--------------------------------- +/// @name Inserting a Managed Object +///--------------------------------- + +/** + Inserts a new managed object for the entity for the given name. + + This method is functionally equivalent to the follow code example. + + [NSEntityDescription insertNewObjectForEntityForName:entityName inManagedObjectContext:self]; + + @param entityName The name of an entity. + @return A new, autoreleased, fully configured instance of the class for the entity named entityName. The instance has its entity description set and is inserted into the receiver. + */ +- (id)insertNewObjectForEntityForName:(NSString *)entityName; + +///------------------------------- +/// @name Counting Managed Objects +///------------------------------- + +/** + Convenience method for performing a count of the number of instances of an entity with the given name. + + This method is functionally equivalent to the following code example. + + NSError *error; + NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:entityName]; + fetchRequest.predicate = predicate; + NSUInteger count = [managedObjectContext countForFetchRequest:fetchRequest error:&error]; + + @param entityName The name of an entity. + @param predicate A predicate to limit the search. May be nil. + @param error If there is a problem executing the fetch, upon return contains an instance of NSError that describes the problem. + @return The number of objects a fetch request for the given entity name with the given predicate would have returned if it had been passed to executeFetchRequest:error:, or NSNotFound if an error occurs. + */ +- (NSUInteger)countForEntityForName:(NSString *)entityName predicate:(NSPredicate *)predicate error:(NSError **)error; + +///------------------------------------------------- +/// @name Saving the Context to the Persistent Store +///------------------------------------------------- + +/** + Saves the receiver and then traverses up the parent context chain until a parent managed object context with a nil parent is found. If the final ancestor context does not have a reference to the persistent store coordinator, then a warning is generated and the method returns NO. + + @param error If there is a problem saving the receiver or any of its ancestor contexts, upon return contains an pointer to an instance of NSError that describes the problem. + @return YES if the save to the persistent store was successful, else NO. + */ +- (BOOL)saveToPersistentStore:(NSError **)error; + +@end diff --git a/Pods/RestKit/Code/CoreData/NSManagedObjectContext+RKAdditions.m b/Pods/RestKit/Code/CoreData/NSManagedObjectContext+RKAdditions.m new file mode 100644 index 0000000..8f22e10 --- /dev/null +++ b/Pods/RestKit/Code/CoreData/NSManagedObjectContext+RKAdditions.m @@ -0,0 +1,84 @@ +// +// NSManagedObjectContext+RKAdditions.m +// RestKit +// +// Created by Blake Watters on 3/14/12. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import +#import "NSManagedObjectContext+RKAdditions.h" +#import "RKLog.h" + +@implementation NSManagedObjectContext (RKAdditions) + +- (id)insertNewObjectForEntityForName:(NSString *)entityName +{ + return [NSEntityDescription insertNewObjectForEntityForName:entityName inManagedObjectContext:self]; +} + +- (NSUInteger)countForEntityForName:(NSString *)entityName predicate:(NSPredicate *)predicate error:(NSError **)error +{ + NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:entityName]; + fetchRequest.predicate = predicate; + return [self countForFetchRequest:fetchRequest error:error]; +} + +- (BOOL)saveToPersistentStore:(NSError **)error +{ + __block NSError *localError = nil; + NSManagedObjectContext *contextToSave = self; + while (contextToSave) { + __block BOOL success; + + /** + To work around issues in ios 5 first obtain permanent object ids for any inserted objects. If we don't do this then its easy to get an `NSObjectInaccessibleException`. This happens when: + + 1. Create new object on main context and save it. + 2. At this point you may or may not call obtainPermanentIDsForObjects for the object, it doesn't matter + 3. Update the object in a private child context. + 4. Save the child context to the parent context (the main one) which will work, + 5. Save the main context - a NSObjectInaccessibleException will occur and Core Data will either crash your app or lock it up (a semaphore is not correctly released on the first error so the next fetch request will block forever. + */ + __block BOOL obtained; + [contextToSave performBlockAndWait:^{ + obtained = [contextToSave obtainPermanentIDsForObjects:[[contextToSave insertedObjects] allObjects] error:&localError]; + }]; + if (!obtained) { + if (error) *error = localError; + return NO; + } + + [contextToSave performBlockAndWait:^{ + success = [contextToSave save:&localError]; + if (! success && localError == nil) RKLogWarning(@"Saving of managed object context failed, but a `nil` value for the `error` argument was returned. This typically indicates an invalid implementation of a key-value validation method exists within your model. This violation of the API contract may result in the save operation being mis-interpretted by callers that rely on the availability of the error."); + }]; + + if (! success) { + if (error) *error = localError; + return NO; + } + + if (! contextToSave.parentContext && contextToSave.persistentStoreCoordinator == nil) { + RKLogWarning(@"Reached the end of the chain of nested managed object contexts without encountering a persistent store coordinator. Objects are not fully persisted."); + return NO; + } + contextToSave = contextToSave.parentContext; + } + + return YES; +} + +@end diff --git a/Pods/RestKit/Code/CoreData/RKConnectionDescription.h b/Pods/RestKit/Code/CoreData/RKConnectionDescription.h new file mode 100644 index 0000000..fc3ecb4 --- /dev/null +++ b/Pods/RestKit/Code/CoreData/RKConnectionDescription.h @@ -0,0 +1,164 @@ +// +// RKConnectionDescription.h +// RestKit +// +// Created by Blake Watters on 11/20/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import + +/** + The `RKConnectionDescription` class describes a means for connecting a Core Data relationship. Connections can be established either by foreign key, in which case one or more attribute values on the source entity correspond to matching values on the destination entity, or by key path, in which case a key path is evaluated on the object graph to obtain a value for the relationship. Connection objects are used by instances of `RKRelationshipConnectionOperation` to connect a relationship of a given managed object. + + ## Foreign Key Connections + + A foreign key connection is established by identifying managed objects within a context which have corresponding values on the source and destination objects. This is typically used to model relationships in the same way one would within a relational database. + + For example, consider the example of a `User` entity that has a to-many relationship named 'projects' for the `Project` entity. Within the `User` entity, there is an attribute named 'userID' that models the value for a given user's primary key as provided to the application by the remote backend API with which it is communicating. Within the `Project` entity, a corresponding 'userID' attribute exists specifying the value of the primary key for the `User` that owns the project. The applications loads each of these object representations independently from the '/me/profile' and '/projects' resources. The JSON representation returned for a given `Project` entity looks something like: + + { "project": + { "id": 12345, + "name": "My Project", + "userID": 1 + } + } + + When this representation is mapped to a managed object for the `Project` entity, the 'user' relationship cannot be mapped directly because there is no nested representation -- only the primary key is available. In this case, the relationship can be connected by describing the association between the entities with an `RKConnectionDescription` object: + + NSEntityDescription *projectEntity = [NSEntityDescription entityForName:@"Project" inManagedObjectContext:managedObjectContext]; + NSRelationshipDescription *userRelationship = [projectEntity relationshipsByName][@"user"]; + RKConnectionDescription *connection = [[RKConnectionDescription alloc] initWithRelationship:userRelationship attributes:@{ @"userID": @"userID" }]; + + Note that the value for the `attributes` argument is provided as a dictionary. Each pair within the dictionary correspond to an attribute pair in which the key is an attribute on the source entity (in this case, the `Project`) and the value is the destination entity (in this case, the `User`). + + Any number of attribute pairs may be specified, but all values must match for the connection to be satisfied and the relationship's value to be set. + + ### Connecting with Collection Values + + Connections can be established by a collection of values. For example, imagine that the previously described project representation has been extended to include a list of team members who are working on the project: + + { "project": + { "id": 12345, + "name": "My Project", + "userID": 1, + "teamMemberIDs": [1, 2, 3, 4] + } + } + + The 'teamMemberIDs' contains an array specifying the ID's of the `User` objects who are collaborating on the project, which corresponds to a to-many relationship named 'teamMembers' on the `Project` entity. In this case, the 'teamMemberIDs' could be mapped on to an `NSArray` or `NSSet` property on the `Project` entity and then connected: + + NSEntityDescription *projectEntity = [NSEntityDescription entityForName:@"Project" inManagedObjectContext:managedObjectContext]; + NSRelationshipDescription *teamMembers = [projectEntity relationshipsByName][@"teamMembers"]; // To many relationship for the `User` entity + RKConnectionDescription *connection = [[RKConnectionDescription alloc] initWithRelationship:teamMembers attributes:@{ @"teamMemberIDs": @"userID" }]; + + When evaluating the above JSON, the connection would be established for the 'teamMembers' relationship to the `User` entities whose userID's are 1, 2, 3 or 4. + + Note that collections of attribute values are always interpetted as logic OR's, but compound connections are aggregated as a logical AND. For example, if we were to add a second connecting attribute for the "gender" property and include `"gender": "male"` in the JSON, the connection would be made to all `User` managed objects whose ID is 1, 2, 3, OR 4 AND whose gender is "male". + + ## Key Path Connections + + A key path connection is established by evaluating the key path of the connection against the managed object being connected. The returned value has type transformation applied and is then assigned to the relationship. + + @see `RKManagedObjectMappingOperationDataSource` + @see `RKRelationshipConnectionOperation` + */ +@interface RKConnectionDescription : NSObject + +///----------------------------------------------- +/// @name Connecting Relationships by Foreign Keys +///----------------------------------------------- + +/** + Initializes the receiver with a given relationship and a dictionary of attributes specifying how to connect the relationship. + + @param relationship The relationship to be connected. + @param sourceToDestinationEntityAttributes A dictionary specifying how attributes on the source entity correspond to attributes on the destination entity. + @return The receiver, initialized with the given relationship and attributes. + */ +- (instancetype)initWithRelationship:(NSRelationshipDescription *)relationship attributes:(NSDictionary *)sourceToDestinationEntityAttributes; + +/** + The dictionary of attributes specifying how attributes on the source entity for the relationship correspond to attributes on the destination entity. + + This attribute is `nil` unless the value of `isForeignKeyConnection` is `YES`. + */ +@property (nonatomic, copy, readonly) NSDictionary *attributes; + +/** + Returns a Boolean value indicating if the receiver describes a foreign key connection. + + @return `YES` if the receiver describes a foreign key connection, else `NO`. + */ +@property (nonatomic, getter=isForeignKeyConnection, readonly) BOOL foreignKeyConnection; + +///------------------------------------------- +/// @name Connecting Relationships by Key Path +///------------------------------------------- + +/** + Initializes the receiver with a given relationship and key path. + + @param relationship The relationship to be connected. + @param keyPath The key path from which to read the value that is to be set for the relationship. + @return The receiver, initialized with the given relationship and key path. + */ +- (instancetype)initWithRelationship:(NSRelationshipDescription *)relationship keyPath:(NSString *)keyPath; + +/** + The key path that is to be evaluated to obtain the value for the relationship. + + This attribute is `nil` unless the value of `isKeyPathConnection` is `YES`. + */ +@property (nonatomic, copy, readonly) NSString *keyPath; + +/** + Returns a Boolean value indicating if the receiver describes a key path connection. + + @return `YES` if the receiver describes a key path connection, else `NO`. + */ +@property (nonatomic, getter=isKeyPathConnection, readonly) BOOL keyPathConnection; + +///------------------------------------------------- +/// @name Accessing the Relationship to be Connected +///------------------------------------------------- + +/** + Returns the relationship that is to be connected. + */ +@property (nonatomic, strong, readonly) NSRelationshipDescription *relationship; + +///---------------------------- +/// @name Setting the Predicate +///---------------------------- + +/** + Returns a Boolean value that determines if the connection includes subentities. If `NO`, then the connection will only be established to objects of exactly the entity specified by the relationship's entity. If `YES`, then the connection will be established to all objects of the relationship's entity and all subentities. + + **Default**: `YES` + */ +@property (nonatomic, assign) BOOL includesSubentities; + +/** + An optional predicate for conditionally evaluating the connection based on the state of the source object. + */ +@property (nonatomic, strong) NSPredicate *sourcePredicate; + +/** + An optional predicate for filtering objects to be connected. + */ +@property (nonatomic, copy) NSPredicate *destinationPredicate; + +@end diff --git a/Pods/RestKit/Code/CoreData/RKConnectionDescription.m b/Pods/RestKit/Code/CoreData/RKConnectionDescription.m new file mode 100644 index 0000000..ee47003 --- /dev/null +++ b/Pods/RestKit/Code/CoreData/RKConnectionDescription.m @@ -0,0 +1,142 @@ +// +// RKConnectionDescription.m +// RestKit +// +// Created by Blake Watters on 11/20/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKConnectionDescription.h" + +static NSSet *RKSetWithInvalidAttributesForEntity(NSArray *attributes, NSEntityDescription *entity) +{ + NSMutableSet *attributesSet = [NSMutableSet setWithArray:attributes]; + NSSet *validAttributeNames = [NSSet setWithArray:[[entity attributesByName] allKeys]]; + [attributesSet minusSet:validAttributeNames]; + return attributesSet; +} + +// Provides support for connecting a relationship by +@interface RKForeignKeyConnectionDescription : RKConnectionDescription +@end + +// Provides support for connecting a relationship by traversing the object graph +@interface RKKeyPathConnectionDescription : RKConnectionDescription +@end + +@interface RKConnectionDescription () +@property (nonatomic, strong, readwrite) NSRelationshipDescription *relationship; +@property (nonatomic, copy, readwrite) NSDictionary *attributes; +@property (nonatomic, copy, readwrite) NSString *keyPath; +@end + +@implementation RKConnectionDescription + +- (instancetype)initWithRelationship:(NSRelationshipDescription *)relationship attributes:(NSDictionary *)attributes +{ + NSParameterAssert(relationship); + NSParameterAssert(attributes); + if (! [attributes count]) [NSException raise:NSInvalidArgumentException format:@"Cannot connect a relationship without at least one pair of attributes describing the connection"]; + NSSet *invalidSourceAttributes = RKSetWithInvalidAttributesForEntity([attributes allKeys], [relationship entity]); + if ([invalidSourceAttributes count]) [NSException raise:NSInvalidArgumentException format:@"Cannot connect relationship: invalid attributes given for source entity '%@': %@", [[relationship entity] name], [[invalidSourceAttributes allObjects] componentsJoinedByString:@", "]]; + NSSet *invalidDestinationAttributes = RKSetWithInvalidAttributesForEntity([attributes allValues], [relationship destinationEntity]); + if ([invalidDestinationAttributes count]) [NSException raise:NSInvalidArgumentException format:@"Cannot connect relationship: invalid attributes given for destination entity '%@': %@", [[relationship destinationEntity] name], [[invalidDestinationAttributes allObjects] componentsJoinedByString:@", "]]; + + self = [[RKForeignKeyConnectionDescription alloc] init]; + if (self) { + self.relationship = relationship; + self.attributes = attributes; + self.includesSubentities = YES; + } + return self; +} + +- (instancetype)initWithRelationship:(NSRelationshipDescription *)relationship keyPath:(NSString *)keyPath +{ + NSParameterAssert(relationship); + NSParameterAssert(keyPath); + self = [[RKKeyPathConnectionDescription alloc] init]; + if (self) { + self.relationship = relationship; + self.keyPath = keyPath; + } + return self; +} + +- (instancetype)init +{ + if ([self class] == [RKConnectionDescription class]) { + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:[NSString stringWithFormat:@"%@ Failed to call designated initializer. " + "Invoke initWithRelationship:attributes: instead.", + NSStringFromClass([self class])] + userInfo:nil]; + } + return [super init]; +} + +- (id)copyWithZone:(NSZone *)zone +{ + if ([self isForeignKeyConnection]) { + return [[[self class] allocWithZone:zone] initWithRelationship:self.relationship attributes:self.attributes]; + } else if ([self isKeyPathConnection]) { + return [[[self class] allocWithZone:zone] initWithRelationship:self.relationship keyPath:self.keyPath]; + } + + return nil; +} + +- (BOOL)isForeignKeyConnection +{ + return NO; +} + +- (BOOL)isKeyPathConnection +{ + return NO; +} + +@end + +@implementation RKForeignKeyConnectionDescription + +- (BOOL)isForeignKeyConnection +{ + return YES; +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@"<%@:%p connecting Relationship '%@' from Entity '%@' to Destination Entity '%@' with attributes=%@>", + NSStringFromClass([self class]), self, [self.relationship name], [[self.relationship entity] name], + [[self.relationship destinationEntity] name], self.attributes]; +} + +@end + +@implementation RKKeyPathConnectionDescription + +- (BOOL)isKeyPathConnection +{ + return YES; +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@"<%@:%p connecting Relationship '%@' of Entity '%@' with keyPath=%@>", + NSStringFromClass([self class]), self, [self.relationship name], [[self.relationship entity] name], self.keyPath]; +} + +@end diff --git a/Pods/RestKit/Code/CoreData/RKCoreData.h b/Pods/RestKit/Code/CoreData/RKCoreData.h new file mode 100644 index 0000000..01c826e --- /dev/null +++ b/Pods/RestKit/Code/CoreData/RKCoreData.h @@ -0,0 +1,26 @@ +// +// RKCoreData.h +// RestKit +// +// Created by Samuel E. Giddins on 4/23/14. +// Copyright (c) 2014 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#ifndef RestKit_RKCoreData_h +#define RestKit_RKCoreData_h + +#import "CoreData.h" + +#endif diff --git a/Pods/RestKit/Code/CoreData/RKEntityByAttributeCache.h b/Pods/RestKit/Code/CoreData/RKEntityByAttributeCache.h new file mode 100644 index 0000000..c727462 --- /dev/null +++ b/Pods/RestKit/Code/CoreData/RKEntityByAttributeCache.h @@ -0,0 +1,199 @@ +// +// RKEntityByAttributeCache.h +// RestKit +// +// Created by Blake Watters on 5/1/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import + +/** + The `RKEntityByAttributeCache` class provides an in-memory caching mechanism for managed objects instances of an entity in a managed object context with the value of one of the object's attributes acting as the cache key. When loaded, the cache will retrieve all instances of an entity from the store and build a dictionary mapping values for the given cache key attribute to the managed object ID for all objects matching the value. The cache can then be used to quickly retrieve objects by attribute value for the cache key without executing another fetch request against the managed object context. This can provide a large performance improvement when a large number of objects are being retrieved using a particular attribute as the key. + + `RKEntityByAttributeCache` instances are used by the `RKEntityCache` to provide caching for multiple entities at once. + + @bug Please note that the `RKEntityByAttribute` cache is implemented using a `NSFetchRequest` with a result type of `NSDictionaryResultType`. This means that the cache **cannot** load pending object instances via a fetch from the `load` method. Pending objects must be manually added to the cache via `addObject:` if it is desirable for the pending objects to be retrieved by subsequent invocations of `objectWithAttributeValue:inContext:` and `objectsWithAttributeValue:inContext:` prior to a save. + + This is a limitation imposed by Core Data. The dictionary result type implementation is leveraged instead a normal fetch request because it offers very large performance and memory utilization improvements by avoiding construction of managed object instances and faulting. + + @see `RKEntityCache` + */ +@interface RKEntityByAttributeCache : NSObject + +///----------------------- +/// @name Creating a Cache +///----------------------- + +/** + Initializes the receiver with a given entity, attribute, and managed object context. + + @param entity The Core Data entity description for the managed objects being cached. + @param attributeNames An array of attribute names used as the cache keys. + @param context The managed object context the cache retrieves the cached objects from. + @return The receiver, initialized with the given entity, attribute, and managed object + context. + */ +- (instancetype)initWithEntity:(NSEntityDescription *)entity attributes:(NSArray *)attributeNames managedObjectContext:(NSManagedObjectContext *)context; + +///----------------------------- +/// @name Getting Cache Identity +///----------------------------- + +/** + The Core Data entity description for the managed objects being cached. + */ +@property (nonatomic, readonly) NSEntityDescription *entity; + +/** + An array of attribute names specifying attributes of the cached entity that act as the cache key. + */ +@property (nonatomic, readonly) NSArray *attributes; + +/** + The managed object context the receiver fetches cached objects from. + */ +@property (nonatomic, readonly) NSManagedObjectContext *managedObjectContext; + +/** + The queue on which to dispatch callbacks for asynchronous operations. When `nil`, the main queue is used. + + **Default**: `nil` + */ +@property (nonatomic, assign) dispatch_queue_t callbackQueue; + +///------------------------------------- +/// @name Loading and Flushing the Cache +///------------------------------------- + +/** + Loads the cache by finding all instances of the configured entity and building + an association between the value of the cached attribute's value and the + managed object ID for the object. + + @param completion A block to execute when the cache has finished loading. + */ +- (void)load:(void (^)(void))completion; + +/** + Flushes the cache by releasing all cache attribute value to managed object ID associations. + + @param completion A block to execute when the cache has finished flushing. + */ +- (void)flush:(void (^)(void))completion; + +///----------------------------- +/// @name Inspecting Cache State +///----------------------------- + +/** + A Boolean value indicating if the cache has loaded associations between cache attribute values and managed object ID's. + */ +@property (nonatomic, getter=isLoaded, readonly) BOOL loaded; + +/** + Returns a count of the total number of cached objects. + */ +@property (nonatomic, readonly) NSUInteger count; + +/** + Returns the total number of cached objects whose attributes match the values in the given dictionary of attribute values. + + @param attributeValues The value for the cache key attribute to retrieve a count of the objects with a matching value. + @return The number of objects in the cache with the given value for the cache attribute of the receiver. + */ +- (NSUInteger)countWithAttributeValues:(NSDictionary *)attributeValues; + +/** + Returns the number of unique attribute values contained within the receiver. + + @return The number of unique attribute values within the receiver. + */ +@property (nonatomic, readonly) NSUInteger countOfAttributeValues; + +/** + Returns a Boolean value that indicates whether a given object is present + in the cache. + + @param object An object. + @return YES if object is present in the cache, otherwise NO. + */ +- (BOOL)containsObject:(NSManagedObject *)object; + +/** + Returns a Boolean value that indicates whether one of more objects is present + in the cache with a given value of the cache key attribute. + + @param attributeValues The value with which to check the cache for objects with a matching value. + @return YES if one or more objects with the given value for the cache key attribute is present in the cache, otherwise NO. + */ +- (BOOL)containsObjectWithAttributeValues:(NSDictionary *)attributeValues; + +/** + Returns the first object with a matching value for the cache key attributes in a given managed object context. + + @param attributeValues A value for the cache key attribute. + @param context The managed object context to retrieve the object from. + @return An object with the value of attribute matching attributeValue or nil. + */ +- (NSManagedObject *)objectWithAttributeValues:(NSDictionary *)attributeValues inContext:(NSManagedObjectContext *)context; + +/** + Returns the collection of objects with a matching value for the cache key attribute in a given managed object context. + + @param attributeValues A value for the cache key attribute. + @param context The managed object context to retrieve the objects from. + @return An array of objects with the value of attribute matching attributeValue or an empty array. + */ +- (NSSet *)objectsWithAttributeValues:(NSDictionary *)attributeValues inContext:(NSManagedObjectContext *)context; + +///------------------------------ +/// @name Managing Cached Objects +///------------------------------ + +/** + Asynchronously adds a managed object to the cache. + + The object must be an instance of the cached entity. + + @param managedObjects The managed object to add to the cache. + @param completion An optional block to execute once the object has been added to the cache. + */ +- (void)addObjects:(NSSet *)managedObjects completion:(void (^)(void))completion; + +/** + Asynchronously removes a managed object from the cache. + + The object must be an instance of the cached entity. + + @param managedObjects The managed object to remove from the cache. + @param completion An optional block to execute once the object has been removed from the cache. + */ +- (void)removeObjects:(NSSet *)managedObjects completion:(void (^)(void))completion; + +@end + +/* + Deprecated in 0.20.1 + + All methods below now accept a completion block + */ +@interface RKEntityByAttributeCache (Deprecations) +- (void)load DEPRECATED_ATTRIBUTE; // use `load:` +- (void)flush DEPRECATED_ATTRIBUTE; // use `flush:` +- (void)addObject:(NSManagedObject *)object DEPRECATED_ATTRIBUTE; // use `addObjects:completion:` +- (void)removeObject:(NSManagedObject *)object DEPRECATED_ATTRIBUTE; // use `removeObjects:completion:` +@property (nonatomic, assign) BOOL monitorsContextForChanges DEPRECATED_ATTRIBUTE; // No longer applies. Consumers are responsible for context change monitoring. Handled by `RKInMemoryManagedObjectCache` +@end diff --git a/Pods/RestKit/Code/CoreData/RKEntityByAttributeCache.m b/Pods/RestKit/Code/CoreData/RKEntityByAttributeCache.m new file mode 100644 index 0000000..6ecac27 --- /dev/null +++ b/Pods/RestKit/Code/CoreData/RKEntityByAttributeCache.m @@ -0,0 +1,442 @@ +// +// RKEntityByAttributeCache.m +// RestKit +// +// Created by Blake Watters on 5/1/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#if TARGET_OS_IPHONE +#import +#endif + +#import "RKEntityByAttributeCache.h" +#import "RKLog.h" +#import "RKPropertyInspector.h" +#import "RKPropertyInspector+CoreData.h" +#import "NSManagedObject+RKAdditions.h" +#import "RKObjectUtilities.h" + +// Set Logging Component +#undef RKLogComponent +#define RKLogComponent RKlcl_cRestKitCoreDataCache + +static id RKCacheKeyValueForEntityAttributeWithValue(NSEntityDescription *entity, NSString *attribute, id value) +{ + if ([value isKindOfClass:[NSString class]] || [value isEqual:[NSNull null]]) { + return value; + } + return [value respondsToSelector:@selector(stringValue)] ? [value stringValue] : value; +} + +static NSString *RKCacheKeyForEntityWithAttributeValues(NSEntityDescription *entity, NSDictionary *attributeValues) +{ + // Performance optimization + if ([attributeValues count] == 1) return [[[attributeValues allValues] lastObject] description]; + NSArray *sortedAttributes = [[attributeValues allKeys] sortedArrayUsingSelector:@selector(compare:)]; + NSMutableArray *sortedValues = [NSMutableArray arrayWithCapacity:[sortedAttributes count]]; + for (NSString *attributeName in sortedAttributes) { + id cacheKeyValue = RKCacheKeyValueForEntityAttributeWithValue(entity, attributeName, attributeValues[attributeName]); + [sortedValues addObject:cacheKeyValue]; + }; + + return [sortedValues componentsJoinedByString:@":"]; +} + +/* + This function recursively calculates a set of cache keys given a dictionary of attribute values. The basic premise is that we wish to decompose all arrays of values within the dictionary into a distinct cache key, as each object within the cache will appear for only one key. + */ +static NSArray *RKCacheKeysForEntityFromAttributeValues(NSEntityDescription *entity, NSDictionary *attributeValues) +{ + NSMutableArray *cacheKeys = [NSMutableArray array]; + NSSet *collectionKeys = [attributeValues keysOfEntriesPassingTest:^BOOL(id key, id obj, BOOL *stop) { + return RKObjectIsCollection(obj); + }]; + + if ([collectionKeys count] > 0) { + for (NSString *attributeName in collectionKeys) { + id attributeValue = attributeValues[attributeName]; + for (id value in attributeValue) { + NSMutableDictionary *mutableAttributeValues = [attributeValues mutableCopy]; + [mutableAttributeValues setValue:value forKey:attributeName]; + [cacheKeys addObjectsFromArray:RKCacheKeysForEntityFromAttributeValues(entity, mutableAttributeValues)]; + } + } + } else { + [cacheKeys addObject:RKCacheKeyForEntityWithAttributeValues(entity, attributeValues)]; + } + + return cacheKeys; +} + +@interface RKEntityByAttributeCache () +@property (nonatomic, strong) NSMutableDictionary *cacheKeysToObjectIDs; +#if OS_OBJECT_USE_OBJC +@property (nonatomic, strong) dispatch_queue_t queue; +#else +@property (nonatomic, assign) dispatch_queue_t queue; +#endif +@end + +@implementation RKEntityByAttributeCache + +- (instancetype)initWithEntity:(NSEntityDescription *)entity attributes:(NSArray *)attributeNames managedObjectContext:(NSManagedObjectContext *)context +{ + NSParameterAssert(entity); + NSParameterAssert(attributeNames); + NSParameterAssert(context); + + self = [self init]; + if (self) { + _entity = entity; + _attributes = attributeNames; + _managedObjectContext = context; + NSString *queueName = [[NSString alloc] initWithFormat:@"%@.%p", @"org.restkit.core-data.entity-by-attribute-cache", self]; + self.queue = dispatch_queue_create([queueName UTF8String], DISPATCH_QUEUE_CONCURRENT); + +#if TARGET_OS_IPHONE + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(didReceiveMemoryWarning:) + name:UIApplicationDidReceiveMemoryWarningNotification + object:nil]; +#endif + } + + return self; +} + +- (void)dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver:self]; + +#if !OS_OBJECT_USE_OBJC + dispatch_release(_queue); + _queue = NULL; +#endif + _callbackQueue = NULL; +} + +- (NSUInteger)count +{ + __block NSUInteger count; + dispatch_sync(self.queue, ^{ + count = [[[self.cacheKeysToObjectIDs allValues] valueForKeyPath:@"@sum.@count"] integerValue]; + }); + return count; +} + +- (NSUInteger)countOfAttributeValues +{ + __block NSUInteger count; + dispatch_sync(self.queue, ^{ + count = [self.cacheKeysToObjectIDs count]; + }); + return count; +} + +- (NSUInteger)countWithAttributeValues:(NSDictionary *)attributeValues +{ + return [[self objectsWithAttributeValues:attributeValues inContext:self.managedObjectContext] count]; +} + +- (void)load:(void (^)(void))completion +{ + NSExpressionDescription* objectIDExpression = [NSExpressionDescription new]; + objectIDExpression.name = @"objectID"; + objectIDExpression.expression = [NSExpression expressionForEvaluatedObject]; + objectIDExpression.expressionResultType = NSObjectIDAttributeType; + + // NOTE: `NSDictionaryResultType` does NOT support fetching pending changes. Pending objects must be manually added to the cache via `addObject:`. + NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; + fetchRequest.entity = self.entity; + fetchRequest.resultType = NSDictionaryResultType; + fetchRequest.propertiesToFetch = [self.attributes arrayByAddingObject:objectIDExpression]; + + [self.managedObjectContext performBlock:^{ + NSError *error = nil; + NSArray *dictionaries = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error]; + if (dictionaries) { + RKLogDebug(@"Retrieved %ld dictionaries for cachable `NSManagedObjectID` objects with fetch request: %@", (long) [dictionaries count], fetchRequest); + } else { + RKLogWarning(@"Failed to load entity cache. Failed to execute fetch request: %@", fetchRequest); + RKLogCoreDataError(error); + } + + dispatch_barrier_async(self.queue, ^{ + RKLogDebug(@"Loading entity cache for Entity '%@' by attributes '%@' in managed object context %@ (concurrencyType = %ld)", + self.entity.name, self.attributes, self.managedObjectContext, (unsigned long)self.managedObjectContext.concurrencyType); + self.cacheKeysToObjectIDs = [NSMutableDictionary dictionary]; + for (NSDictionary *dictionary in dictionaries) { + NSManagedObjectID *objectID = dictionary[@"objectID"]; + NSDictionary *attributeValues = [dictionary dictionaryWithValuesForKeys:self.attributes]; + [self cacheObjectID:objectID forAttributeValues:attributeValues]; + } + + if (completion) dispatch_async(self.callbackQueue ?: dispatch_get_main_queue(), completion); + }); + }]; +} + +- (void)flush:(void (^)(void))completion +{ + dispatch_barrier_async(self.queue, ^{ + RKLogDebug(@"Flushing entity cache for Entity '%@' by attributes '%@'", self.entity.name, self.attributes); + self.cacheKeysToObjectIDs = nil; + if (completion) dispatch_async(self.callbackQueue ?: dispatch_get_main_queue(), completion); + }); +} + +- (BOOL)isLoaded +{ + __block BOOL isLoaded; + dispatch_sync(self.queue, ^{ + isLoaded = (self.cacheKeysToObjectIDs != nil); + }); + return isLoaded; +} + +- (NSManagedObject *)objectForObjectID:(NSManagedObjectID *)objectID inContext:(NSManagedObjectContext *)context +{ + /** + NOTE: + + We use `existingObjectWithID:` as opposed to `objectWithID:` as `objectWithID:` can return us a fault + that will raise an exception when fired. `existingObjectWithID:error:` will return nil if the ID has been + deleted. `objectRegisteredForID:` is also an acceptable approach. + */ + __block NSError *error = nil; + __block NSManagedObject *object; + [context performBlockAndWait:^{ + object = [context existingObjectWithID:objectID error:&error]; + }]; + if (! object) { + // Referential integrity errors often indicates that the temporary objectID does not exist in the specified context + if (error && !([objectID isTemporaryID] && [error code] == NSManagedObjectReferentialIntegrityError)) { + RKLogError(@"Failed to retrieve managed object with ID %@. Error %@\n%@", objectID, [error localizedDescription], [error userInfo]); + } + } + return object; +} + +- (NSManagedObject *)objectWithAttributeValues:(NSDictionary *)attributeValues inContext:(NSManagedObjectContext *)context +{ + NSSet *objects = [self objectsWithAttributeValues:attributeValues inContext:context]; + return ([objects count] > 0) ? [objects anyObject] : nil; +} + +- (NSSet *)objectsWithAttributeValues:(NSDictionary *)attributeValues inContext:(NSManagedObjectContext *)context +{ + NSMutableSet *objects = [NSMutableSet set]; + NSArray *cacheKeys = RKCacheKeysForEntityFromAttributeValues(self.entity, attributeValues); + for (NSString *cacheKey in cacheKeys) { + __block NSSet *objectIDs = nil; + dispatch_sync(self.queue, ^{ + objectIDs = [[NSSet alloc] initWithSet:(self.cacheKeysToObjectIDs)[cacheKey] copyItems:YES]; + }); + if ([objectIDs count]) { + /** + NOTE: + In my benchmarking, retrieving the objects one at a time using existingObjectWithID: is significantly faster + than issuing a single fetch request against all object ID's. + */ + for (NSManagedObjectID *objectID in objectIDs) { + NSManagedObject *object = [self objectForObjectID:objectID inContext:context]; + if (object) { + [objects addObject:object]; + } else { + RKLogDebug(@"Evicting objectID association for attributes %@ of Entity '%@': %@", attributeValues, self.entity.name, objectID); + [self evictObjectID:objectID forAttributeValues:attributeValues]; + } + } + } + } + return objects; +} + +- (void)cacheObjectID:(NSManagedObjectID *)objectID forAttributeValues:(NSDictionary *)attributeValues +{ + NSParameterAssert(objectID); + NSParameterAssert(attributeValues); + NSString *cacheKey = RKCacheKeyForEntityWithAttributeValues(self.entity, attributeValues); + NSMutableSet *objectIDs = (self.cacheKeysToObjectIDs)[cacheKey]; + if (objectIDs) { + if (! [objectIDs containsObject:objectID]) { + [objectIDs addObject:objectID]; + } + } else { + objectIDs = [NSMutableSet setWithObject:objectID]; + } + + if (nil == self.cacheKeysToObjectIDs) self.cacheKeysToObjectIDs = [NSMutableDictionary dictionary]; + [self.cacheKeysToObjectIDs setValue:objectIDs forKey:cacheKey]; +} + +- (void)deleteObjectID:(NSManagedObjectID *)objectID forAttributeValues:(NSDictionary *)attributeValues +{ + NSParameterAssert(objectID); + NSParameterAssert(attributeValues); + NSArray *cacheKeys = RKCacheKeysForEntityFromAttributeValues(self.entity, attributeValues); + for (NSString *cacheKey in cacheKeys) { + NSMutableSet *objectIDs = (self.cacheKeysToObjectIDs)[cacheKey]; + if (objectIDs && [objectIDs containsObject:objectID]) { + [objectIDs removeObject:objectID]; + } + } +} + +- (void)evictObjectID:(NSManagedObjectID *)objectID forAttributeValues:(NSDictionary *)attributeValues +{ + if (attributeValues && [attributeValues count]) { + NSArray *cacheKeys = RKCacheKeysForEntityFromAttributeValues(self.entity, attributeValues); + dispatch_barrier_async(self.queue, ^{ + for (NSString *cacheKey in cacheKeys) { + NSMutableSet *objectIDs = (self.cacheKeysToObjectIDs)[cacheKey]; + if (objectIDs && [objectIDs containsObject:objectID]) { + [objectIDs removeObject:objectID]; + } + } + }); + } else { + RKLogWarning(@"Unable to remove object for object ID %@: empty values dictionary for attributes '%@'", objectID, self.attributes); + } +} + +- (void)addObjects:(NSSet *)managedObjects completion:(void (^)(void))completion +{ + if ([managedObjects count] == 0) { + if (completion) dispatch_async(self.callbackQueue ?: dispatch_get_main_queue(), completion); + return; + } + __block NSEntityDescription *entity; + __block NSDictionary *attributeValues; + __block NSManagedObjectID *objectID; + NSManagedObjectContext *managedObjectContext = [[managedObjects anyObject] managedObjectContext]; + [managedObjectContext performBlockAndWait:^{ + NSMutableDictionary *newObjectIDsToAttributeValues = [NSMutableDictionary dictionaryWithCapacity:[managedObjects count]]; + for (NSManagedObject *managedObject in managedObjects) { + entity = managedObject.entity; + objectID = [managedObject objectID]; + attributeValues = [managedObject dictionaryWithValuesForKeys:self.attributes]; + + NSAssert([entity isKindOfEntity:self.entity], @"Cannot add object with entity '%@' to cache for entity of '%@'", [entity name], [self.entity name]); + newObjectIDsToAttributeValues[objectID] = attributeValues; + } + + if ([newObjectIDsToAttributeValues count]) { + dispatch_barrier_async(self.queue, ^{ + [newObjectIDsToAttributeValues enumerateKeysAndObjectsUsingBlock:^(NSManagedObjectID *objectID, NSDictionary *attributeValues, BOOL *stop) { + [self cacheObjectID:objectID forAttributeValues:attributeValues]; + }]; + + if (completion) dispatch_async(self.callbackQueue ?: dispatch_get_main_queue(), completion); + }); + } else { + if (completion) dispatch_async(self.callbackQueue ?: dispatch_get_main_queue(), completion); + } + }]; +} + +- (void)removeObjects:(NSSet *)managedObjects completion:(void (^)(void))completion +{ + if ([managedObjects count] == 0) { + if (completion) dispatch_async(self.callbackQueue ?: dispatch_get_main_queue(), completion); + return; + } + __block NSEntityDescription *entity; + __block NSDictionary *attributeValues; + __block NSManagedObjectID *objectID; + NSManagedObjectContext *managedObjectContext = [[managedObjects anyObject] managedObjectContext]; + [managedObjectContext performBlock:^{ + NSMutableDictionary *deletedObjectIDsToAttributeValues = [NSMutableDictionary dictionaryWithCapacity:[managedObjects count]]; + for (NSManagedObject *managedObject in managedObjects) { + entity = managedObject.entity; + objectID = [managedObject objectID]; + attributeValues = [managedObject dictionaryWithValuesForKeys:self.attributes]; + + NSAssert([entity isKindOfEntity:self.entity], @"Cannot remove object with entity '%@' from cache for entity of '%@'", [entity name], [self.entity name]); + deletedObjectIDsToAttributeValues[objectID] = attributeValues; + } + + if ([deletedObjectIDsToAttributeValues count]) { + dispatch_barrier_async(self.queue, ^{ + [deletedObjectIDsToAttributeValues enumerateKeysAndObjectsUsingBlock:^(NSManagedObjectID *objectID, NSDictionary *attributeValues, BOOL *stop) { + [self deleteObjectID:objectID forAttributeValues:attributeValues]; + }]; + + if (completion) dispatch_async(self.callbackQueue ?: dispatch_get_main_queue(), completion); + }); + } else { + if (completion) dispatch_async(self.callbackQueue ?: dispatch_get_main_queue(), completion); + } + }]; +} + +- (BOOL)containsObjectWithAttributeValues:(NSDictionary *)attributeValues +{ + return [[self objectsWithAttributeValues:attributeValues inContext:self.managedObjectContext] count] > 0; +} + +- (BOOL)containsObject:(NSManagedObject *)object +{ + __block NSArray *allObjectIDs = nil; + dispatch_sync(self.queue, ^{ + allObjectIDs = [[self.cacheKeysToObjectIDs allValues] valueForKeyPath:@"@distinctUnionOfSets.self"]; + }); + return [allObjectIDs containsObject:object.objectID]; +} + +- (void)didReceiveMemoryWarning:(NSNotification *)notification +{ + [self flush:nil]; +} + +@end + +@implementation RKEntityByAttributeCache (Deprecations) + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-implementations" + +- (void)load DEPRECATED_ATTRIBUTE +{ + [self load:nil]; +} + +- (void)flush DEPRECATED_ATTRIBUTE +{ + [self flush:nil]; +} + +- (void)addObject:(NSManagedObject *)object DEPRECATED_ATTRIBUTE +{ + [self addObjects:[NSSet setWithObject:object] completion:nil]; +} + +- (void)removeObject:(NSManagedObject *)object DEPRECATED_ATTRIBUTE +{ + [self removeObjects:[NSSet setWithObject:object] completion:nil]; +} + +- (void)setMonitorsContextForChanges:(BOOL)monitorsContextForChanges DEPRECATED_ATTRIBUTE +{} + +- (BOOL)monitorsContextForChanges DEPRECATED_ATTRIBUTE +{ + return NO; +} + +#pragma clang diagnostic pop + +@end diff --git a/Pods/RestKit/Code/CoreData/RKEntityCache.h b/Pods/RestKit/Code/CoreData/RKEntityCache.h new file mode 100644 index 0000000..d93c78a --- /dev/null +++ b/Pods/RestKit/Code/CoreData/RKEntityCache.h @@ -0,0 +1,164 @@ +// +// RKEntityCache.h +// RestKit +// +// Created by Blake Watters on 5/2/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import + +@class RKEntityByAttributeCache; + +/** + Instances of `RKEntityCache` provide an in-memory caching mechanism for objects in a Core Data managed object context. Managed objects can be cached by attribute for fast retrieval without repeatedly hitting the Core Data persistent store. This can provide a substantial speed advantage over issuing fetch requests in cases where repeated look-ups of the same data are performed using a small set of attributes as the query key. Internally, the cache entries are maintained as references to the `NSManagedObjectID` of corresponding cached objects. + */ +@interface RKEntityCache : NSObject + +///----------------------------- +/// @name Initializing the Cache +///----------------------------- + +/** + Initializes the receiver with a managed object context containing the entity instances to be cached. + + @param context The managed object context containing objects to be cached. + @returns The receiver, initialized with the given context. + */ +- (instancetype)initWithManagedObjectContext:(NSManagedObjectContext *)context NS_DESIGNATED_INITIALIZER; + +/** + The managed object context with which the receiver is associated. + */ +@property (nonatomic, strong, readonly) NSManagedObjectContext *managedObjectContext; + +///------------------------------------- +/// @name Configuring the Callback Queue +///------------------------------------- + +/** + The queue on which to dispatch callbacks for asynchronous operations. When `nil`, the main queue is used. + + **Default**: `nil` + */ +@property (nonatomic, assign) dispatch_queue_t callbackQueue; + +///------------------------------------ +/// @name Caching Objects by Attributes +///------------------------------------ + +/** + Caches all instances of an entity using the value for an attribute as the cache key. + + @param entity The entity to cache all instances of. + @param attributeNames The attributes to cache the instances by. + */ +- (void)cacheObjectsForEntity:(NSEntityDescription *)entity byAttributes:(NSArray *)attributeNames completion:(void (^)(void))completion; + +/** + Returns a Boolean value indicating if all instances of an entity have been cached by a given attribute name. + + @param entity The entity to check the cache status of. + @param attributeNames The attributes to check the cache status with. + @return YES if the cache has been loaded with instances with the given attribute, else NO. + */ +- (BOOL)isEntity:(NSEntityDescription *)entity cachedByAttributes:(NSArray *)attributeNames; + +/** + Retrieves the first cached instance of a given entity where the specified attribute matches the given value. + + @param entity The entity to search the cache for instances of. + @param attributeValues The attribute values return a match for. + @param context The managed object from which to retrieve the cached results. + @return A matching managed object instance or nil. + @raise NSInvalidArgumentException Raised if instances of the entity and attribute have not been cached. + */ +- (NSManagedObject *)objectForEntity:(NSEntityDescription *)entity withAttributeValues:(NSDictionary *)attributeValues inContext:(NSManagedObjectContext *)context; + +/** + Retrieves all cached instances of a given entity where the specified attribute matches the given value. + + @param entity The entity to search the cache for instances of. + @param attributeValues The attribute values return a match for. + @param context The managed object from which to retrieve the cached results. + @return All matching managed object instances or nil. + @raise NSInvalidArgumentException Raised if instances of the entity and attribute have not been cached. + */ +- (NSSet *)objectsForEntity:(NSEntityDescription *)entity withAttributeValues:(NSDictionary *)attributeValues inContext:(NSManagedObjectContext *)context; + +///----------------------------------------------------------------------------- +// @name Accessing Underlying Caches +///----------------------------------------------------------------------------- + +/** + Retrieves the underlying entity attribute cache for a given entity and attribute. + + @param entity The entity to retrieve the entity attribute cache object for. + @param attributeNames The attribute to retrieve the entity attribute cache object for. + @return The entity attribute cache for the given entity and attribute, or nil if none was found. + */ +- (RKEntityByAttributeCache *)attributeCacheForEntity:(NSEntityDescription *)entity attributes:(NSArray *)attributeNames; + +/** + Retrieves all entity attributes caches for a given entity. + + @param entity The entity to retrieve the collection of entity attribute caches for. + @return An array of entity attribute cache objects for the given entity or an empty array if none were found. + */ +- (NSArray *)attributeCachesForEntity:(NSEntityDescription *)entity; + +///----------------------------------------------------------------------------- +// @name Managing the Cache +///----------------------------------------------------------------------------- + +/** + Flushes the entity cache by sending a flush message to each entity attribute cache contained within the receiver. + + @param completion An optional block to be executed when the flush has completed. + @see [RKEntityByAttributeCache flush] + */ +- (void)flush:(void (^)(void))completion; + +/** + Adds the given set of objects to all entity attribute caches for the object's entity contained within the receiver. + + @param objects The set of objects to add to the appropriate entity attribute caches. + @param completion An optional block to be executed when the object addition has completed. + */ +- (void)addObjects:(NSSet *)objects completion:(void (^)(void))completion; + +/** + Removes the given set of objects from all entity attribute caches for the object's entity contained within the receiver. + + @param objects The set of objects to remove from the appropriate entity attribute caches. + @param completion An optional block to be executed when the object removal has completed. + */ +- (void)removeObjects:(NSSet *)objects completion:(void (^)(void))completion; + +/** + Returns a Boolean value that indicates if the receiver contains the given object in any of its attribute caches. + + @param managedObject The object to check for. + @return `YES` if the receiver contains the given object in one or more of its caches, else `NO`. + */ +- (BOOL)containsObject:(NSManagedObject *)managedObject; + +@end + +// Deprecated in v0.20.1 +@interface RKEntityCache (Deprecations) +- (void)addObject:(NSManagedObject *)object DEPRECATED_ATTRIBUTE; // use `addObjects:completion:` +- (void)removeObject:(NSManagedObject *)object DEPRECATED_ATTRIBUTE; // use `removeObjects:completion:` +@end diff --git a/Pods/RestKit/Code/CoreData/RKEntityCache.m b/Pods/RestKit/Code/CoreData/RKEntityCache.m new file mode 100644 index 0000000..90241db --- /dev/null +++ b/Pods/RestKit/Code/CoreData/RKEntityCache.m @@ -0,0 +1,230 @@ +// +// RKEntityCache.m +// RestKit +// +// Created by Blake Watters on 5/2/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKEntityCache.h" +#import "RKEntityByAttributeCache.h" + +@interface RKEntityCache () +@property (nonatomic, strong) NSMutableSet *attributeCaches; +@end + +@implementation RKEntityCache + +- (instancetype)initWithManagedObjectContext:(NSManagedObjectContext *)context +{ + NSAssert(context, @"Cannot initialize entity cache with a nil context"); + self = [super init]; + if (self) { + _managedObjectContext = context; + _attributeCaches = [[NSMutableSet alloc] init]; + } + + return self; +} + +- (instancetype)init +{ + return [self initWithManagedObjectContext:nil]; +} + +- (void)cacheObjectsForEntity:(NSEntityDescription *)entity byAttributes:(NSArray *)attributeNames completion:(void (^)(void))completion +{ + NSParameterAssert(entity); + NSParameterAssert(attributeNames); + RKEntityByAttributeCache *attributeCache = [self attributeCacheForEntity:entity attributes:attributeNames]; + if (attributeCache && !attributeCache.isLoaded) { + [attributeCache load:completion]; + } else { + attributeCache = [[RKEntityByAttributeCache alloc] initWithEntity:entity attributes:attributeNames managedObjectContext:self.managedObjectContext]; + attributeCache.callbackQueue = self.callbackQueue; + [attributeCache load:completion]; + [self.attributeCaches addObject:attributeCache]; + } +} + +- (BOOL)isEntity:(NSEntityDescription *)entity cachedByAttributes:(NSArray *)attributeNames +{ + NSParameterAssert(entity); + NSParameterAssert(attributeNames); + RKEntityByAttributeCache *attributeCache = [self attributeCacheForEntity:entity attributes:attributeNames]; + return (attributeCache && attributeCache.isLoaded); +} + +- (NSManagedObject *)objectForEntity:(NSEntityDescription *)entity withAttributeValues:(NSDictionary *)attributeValues inContext:(NSManagedObjectContext *)context +{ + NSParameterAssert(entity); + NSParameterAssert(attributeValues); + NSParameterAssert(context); + RKEntityByAttributeCache *attributeCache = [self attributeCacheForEntity:entity attributes:[attributeValues allKeys]]; + if (attributeCache) { + return [attributeCache objectWithAttributeValues:attributeValues inContext:context]; + } + + return nil; +} + +- (NSSet *)objectsForEntity:(NSEntityDescription *)entity withAttributeValues:(NSDictionary *)attributeValues inContext:(NSManagedObjectContext *)context +{ + NSParameterAssert(entity); + NSParameterAssert(attributeValues); + NSParameterAssert(context); + RKEntityByAttributeCache *attributeCache = [self attributeCacheForEntity:entity attributes:[attributeValues allKeys]]; + if (attributeCache) { + return [attributeCache objectsWithAttributeValues:attributeValues inContext:context]; + } + + return [NSSet set]; +} + +- (RKEntityByAttributeCache *)attributeCacheForEntity:(NSEntityDescription *)entity attributes:(NSArray *)attributeNames +{ + NSParameterAssert(entity); + NSParameterAssert(attributeNames); + for (RKEntityByAttributeCache *cache in [self.attributeCaches copy]) { + if ([cache.entity isEqual:entity] && [cache.attributes isEqualToArray:attributeNames]) { + return cache; + } + } + + return nil; +} + +- (NSSet *)attributeCachesForEntity:(NSEntityDescription *)entity +{ + NSAssert(entity, @"Cannot retrieve attribute caches for a nil entity"); + NSMutableSet *set = [NSMutableSet set]; + for (RKEntityByAttributeCache *cache in [self.attributeCaches copy]) { + if ([cache.entity isEqual:entity]) { + [set addObject:cache]; + } + } + + return [NSSet setWithSet:set]; +} + +- (void)waitForDispatchGroup:(dispatch_group_t)dispatchGroup withCompletionBlock:(void (^)(void))completion +{ + if (completion) { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),^{ + dispatch_group_wait(dispatchGroup, DISPATCH_TIME_FOREVER); +#if !OS_OBJECT_USE_OBJC + dispatch_release(dispatchGroup); +#endif + dispatch_async(self.callbackQueue ?: dispatch_get_main_queue(), completion); + }); + } +} + +- (void)flush:(void (^)(void))completion +{ + dispatch_group_t dispatchGroup = completion ? dispatch_group_create() : NULL; + for (RKEntityByAttributeCache *cache in self.attributeCaches) { + if (dispatchGroup) dispatch_group_enter(dispatchGroup); + [cache flush:^{ + if (dispatchGroup) dispatch_group_leave(dispatchGroup); + }]; + } + if (dispatchGroup) [self waitForDispatchGroup:dispatchGroup withCompletionBlock:completion]; +} + +- (void)addObject:(NSManagedObject *)object completion:(void (^)(void))completion +{ + NSAssert(object, @"Cannot add a nil object to the cache"); + dispatch_group_t dispatchGroup = completion ? dispatch_group_create() : NULL; + NSArray *attributeCaches = [self attributeCachesForEntity:object.entity]; + NSSet *objects = [NSSet setWithObject:object]; + for (RKEntityByAttributeCache *cache in attributeCaches) { + if (dispatchGroup) dispatch_group_enter(dispatchGroup); + [cache addObjects:objects completion:^{ + if (dispatchGroup) dispatch_group_leave(dispatchGroup); + }]; + } + if (dispatchGroup) [self waitForDispatchGroup:dispatchGroup withCompletionBlock:completion]; +} + +- (void)removeObject:(NSManagedObject *)object completion:(void (^)(void))completion +{ + NSAssert(object, @"Cannot remove a nil object from the cache"); + NSArray *attributeCaches = [self attributeCachesForEntity:object.entity]; + NSSet *objects = [NSSet setWithObject:object]; + dispatch_group_t dispatchGroup = completion ? dispatch_group_create() : NULL; + for (RKEntityByAttributeCache *cache in attributeCaches) { + if (dispatchGroup) dispatch_group_enter(dispatchGroup); + [cache removeObjects:objects completion:^{ + if (dispatchGroup) dispatch_group_leave(dispatchGroup); + }]; + } + if (dispatchGroup) [self waitForDispatchGroup:dispatchGroup withCompletionBlock:completion]; +} + +- (void)addObjects:(NSSet *)objects completion:(void (^)(void))completion +{ + dispatch_group_t dispatchGroup = completion ? dispatch_group_create() : NULL; + NSSet *distinctEntities = [objects valueForKeyPath:@"entity"]; + for (NSEntityDescription *entity in distinctEntities) { + NSArray *attributeCaches = [self attributeCachesForEntity:entity]; + if ([attributeCaches count]) { + NSMutableSet *objectsToAdd = [NSMutableSet set]; + for (NSManagedObject *managedObject in objects) { + if ([managedObject.entity isEqual:entity]) [objectsToAdd addObject:managedObject]; + } + for (RKEntityByAttributeCache *cache in attributeCaches) { + if (dispatchGroup) dispatch_group_enter(dispatchGroup); + [cache addObjects:objectsToAdd completion:^{ + if (dispatchGroup) dispatch_group_leave(dispatchGroup); + }]; + } + } + } + if (dispatchGroup) [self waitForDispatchGroup:dispatchGroup withCompletionBlock:completion]; +} + +- (void)removeObjects:(NSSet *)objects completion:(void (^)(void))completion +{ + dispatch_group_t dispatchGroup = completion ? dispatch_group_create() : NULL; + NSSet *distinctEntities = [objects valueForKeyPath:@"entity"]; + for (NSEntityDescription *entity in distinctEntities) { + NSArray *attributeCaches = [self attributeCachesForEntity:entity]; + if ([attributeCaches count]) { + NSMutableSet *objectsToRemove = [NSMutableSet set]; + for (NSManagedObject *managedObject in objects) { + if ([managedObject.entity isEqual:entity]) [objectsToRemove addObject:managedObject]; + } + for (RKEntityByAttributeCache *cache in attributeCaches) { + if (dispatchGroup) dispatch_group_enter(dispatchGroup); + [cache removeObjects:objectsToRemove completion:^{ + if (dispatchGroup) dispatch_group_leave(dispatchGroup); + }]; + } + } + } + if (dispatchGroup) [self waitForDispatchGroup:dispatchGroup withCompletionBlock:completion]; +} + +- (BOOL)containsObject:(NSManagedObject *)managedObject +{ + for (RKEntityByAttributeCache *attributeCache in [self attributeCachesForEntity:managedObject.entity]) { + if ([attributeCache containsObject:managedObject]) return YES; + } + + return NO; +} + +@end diff --git a/Pods/RestKit/Code/CoreData/RKEntityMapping.h b/Pods/RestKit/Code/CoreData/RKEntityMapping.h new file mode 100644 index 0000000..65be055 --- /dev/null +++ b/Pods/RestKit/Code/CoreData/RKEntityMapping.h @@ -0,0 +1,307 @@ +// +// RKEntityMapping.h +// RestKit +// +// Created by Blake Watters on 5/31/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import +#import "RKObjectMapping.h" +#import "RKConnectionDescription.h" +#import "RKMacros.h" + +@class RKManagedObjectStore; + +/** + `RKEntityMapping` objects model an object mapping with a Core Data destination entity. + + ## Entity Identification + + One of the fundamental problems when object mapping representations into Core Data entities is determining if a new object should be created or an existing object should be updated. In an entity mapping, one or more attributes can be designated as being used for identification purposes via the `identificationAttributes` property. Typically the values of these attributes are populated by attribute mappings. It is common practice to use a single attribute corresponding to the primary key of the remote resource being mapped, but an arbitrary number of attributes may be specified for identification. Identifying attributes have all type transformations support by the mapper applied before the managed object context is searched, supporting such use-cases as using an `NSDate` as an identifying attribute whose value is mapped from an `NSString`. Identified objects can be further constrained by configuring an identification predicate via the `identificationPredicate` property. The predicate is applied after the managed object has been searched. + + ### Identification Inference + + The `RKEntityMapping` class provides support for inferring identification attributes from the managed object model. When inference is enabled (the default state), the entity is searched for several commonly used identifying attributes and if any is found, the value of the `identificationAttributes` property is automatically configured. Inference is performed by the `RKIdentificationAttributesInferredFromEntity` function. + + When `RKIdentificationAttributesInferredFromEntity` is invoked, the entity is first checked for a user info key specifying the identifying attributes. If the user info of the given entity contains a value for the key 'RKEntityIdentificationAttributes', then that value is used to construct an array of attributes. The user info key must contain a string or an array of strings specifying the names of attributes that exist in the given entity. + + If no attributes are specified in the user info, then the entity is searched for an attribute whose name matches the llama-cased or snake-cased name of the entity. For example, an entity named 'Article' would have an inferred identifying attributes of 'articleID' and 'article_id', and an entity named 'ApprovedComment' would be inferred as 'approvedCommentID' and 'approved_comment_id'. If such an attribute is found within the entity, an array is returned containing the attribute. If none is returned, the the attributes are searched for the following names: + + 1. 'identifier' + 1. 'id' + 1. 'ID' + 1. 'URL' + 1. 'url' + + If any of these attributes are found, then an array is returned containing the attribute. If all possible inferred attributes are exhausted, then `nil` is returned. + + Note that inference will only return a single attribute. Compound attributes must be configured manually via the `identificationAttributes` property. + + ## Connecting Relationships + + When modeling an API into Core Data representation, a common problem is that managed objects that are semantically related are loaded across discrete requests, leaving the Core Data relationships empty. The `RKConnectionDescription` class provides a means for expressing a connection between entities using corresponding attribute values or by key path. Please refer to the documentation accompanying the `RKConnectionDescription` class and the `addConnectionForRelationship:connectedBy:` method of this class. + + @see `RKConnectionDescription` + */ +@interface RKEntityMapping : RKObjectMapping + +///----------------------------------------------------------------------------- +/// @name Initializing an Entity Mapping +///----------------------------------------------------------------------------- + +/** + Initializes the receiver with a given entity. + + @param entity An entity with which to initialize the receiver. + @returns The receiver, initialized with the given entity. + */ +- (instancetype)initWithEntity:(NSEntityDescription *)entity; + +/** + A convenience initializer that creates and returns an entity mapping for the entity with the given name in + the managed object model of the given managed object store. + + This method is functionally equivalent to the following example code: + + NSEntityDescription *entity = [[managedObjectStore.managedObjectModel entitiesByName] objectForKey:entityName]; + return [RKEntityMapping mappingForEntity:entity]; + + @param entityName The name of the entity in the managed object model for which an entity mapping is to be created. + @param managedObjectStore A managed object store containing the managed object model in which an entity with the given name is defined. + @return A new entity mapping for the entity with the given name in the managed object model of the given managed object store. + */ ++ (instancetype)mappingForEntityForName:(NSString *)entityName inManagedObjectStore:(RKManagedObjectStore *)managedObjectStore; + +///--------------------------- +/// @name Accessing the Entity +///--------------------------- + +/** + The Core Data entity description used for this object mapping + */ +@property (nonatomic, strong) NSEntityDescription *entity; + +///------------------------------------------------ +/// @name Configuring Managed Object Identification +///------------------------------------------------ + +/** + The array of `NSAttributeDescription` objects specifying the attributes of the receiver's entity that are used during mapping to determine whether an existing object should be updated or a new managed object should be inserted. Please see the "Entity Identification" section of this document for more information. + + @return An array of identifying attributes or `nil` if none have been configured. + @raises NSInvalidArgumentException Raised if the setter is invoked with the name of an attribute or an `NSAttributeDescription` that does not exist in the receiver's entity. Also raised if the setter is invoked with an empty array. + @warning Note that for convenience, this property may be set with an array containing `NSAttributeDescription` objects or `NSString` objects specifying the names of attributes that exist within the receiver's entity. The getter will always return an array of `NSAttributeDescription` objects. + */ +@property (nonatomic, copy) NSArray *identificationAttributes; + +/** + An optional predicate used to filter identified objects during mapping. + + @return The identification predicate. + */ +@property (nonatomic, copy) NSPredicate *identificationPredicate; + +/** + An optional block which returns a predicate used to filter identified objects during mapping. + + @return The identification predicate block. + */ +@property (nonatomic, copy) NSPredicate *(^identificationPredicateBlock)(NSDictionary *representation, NSManagedObjectContext *managedObjectContext); + +/** + An optional attribute of the receiver's entity that can be used to detect modification of a given instance. This is used to improve the performance of mapping operations by skipping the property mappings for a given object if it is found to be not modified. + + A common modification attribute is a 'last modified' or 'updated at' timestamp that specifies the timestamp of the last change to an object. When the `modificationAttribute` is non-nil, the mapper will compare the value returned of the attribute on an existing object instance with the value in the representation being mapped. + + The semantics of the comparison are dependent on the data type of the modification attribute. If the attribute is a string, then the values are compared for equality. If the attribute is a date or a numeric value, then the values will be compared numerically and mapping will be skipped if the value in the representation is greater than the value of the modification attribute stored on the object. + + @raises NSInvalidArgumentException Raised if the attribute given is not a property of the receiver's entity. + */ +@property (nonatomic, strong) NSAttributeDescription *modificationAttribute; + +/** + Sets the `modificationAttribute` to the receiver to the attribute with the specified name. + + The given name must correspond to the name of an attribute within the receiver's entity. + + @param attributeName The name of an attribute in the entity of the receiver. + @raises NSInvalidArgumentException Raised if no attribute could be found with the given name. + */ +- (void)setModificationAttributeForName:(NSString *)attributeName; + +///--------------------------------------------------------------- +/// @name Specifying a Persistent Store for Newly Inserted Objects +///--------------------------------------------------------------- + +/** + The persistent store in which new object instances mapped with the receiver should be inserted. + + If your application makes use of more than one persistent store (i.e. a combination of an in-memory store and a SQLite store), then it can be desirable to specify the persistent store in which newly created managed objects will be assigned. + + **Default**: `nil` + */ +@property (nonatomic, weak) NSPersistentStore *persistentStore; + +///------------------------------------------- +/// @name Configuring Relationship Connections +///------------------------------------------- + +/** + Returns the array of `RKConnectionDescripton` objects configured for connecting relationships during object mapping. + */ +@property (nonatomic, copy, readonly) NSArray *connections; + +/** + Adds a connection to the receiver. + + @param connection The connection to be added. + */ +- (void)addConnection:(RKConnectionDescription *)connection; + +/** + Removes a connection from the receiver. + + @param connection The connection to be removed. + */ +- (void)removeConnection:(RKConnectionDescription *)connection; + +/** + Adds a connection for the specified relationship connected using the attributes specified by the given `NSString`, `NSArray`, or `NSDictionary` object. + + This is a convenience method for flexibly adding a connection to the receiver. The relationship can be specified with by providing an `NSRelationshipDescription` object or an `NSString` specifying the name of the relationship to be connected. The connection specifier can be provided as an `NSString` object, an `NSArray` of `NSString` object, or an `NSDictionary` with `NSString` objects for the keys and values. The string objects specify the name of attributes within the entity and destination entity of the specified relationship. The `RKConnectionDescription` class models a connection as a dictionary in which the keys are `NSString` objects corresponding to the names of attributes in the source entity of the relationship being connected and the values are `NSString` objects corresponding to the names of attributes in the destination entity. + + When the `connectionSpecifier` is an `NSString` value, it is interpretted as the name of an attribute in the specified relationship's entity. The corresponding attribute in the destination entity is determined by invoking the source to destination key transformation block set via `[RKObjectMapping setSourceToDestinationKeyTransformationBlock:]`. If no transformation block is configured, then the destination attribute is assumed to have the same name as the source attribute. For example, consider a model in which there entities named 'User' and 'Project'. The 'User' entity has a to-many relationship to the 'Project' entity named 'projects'. Both the 'User' and the 'Project' entities contain an attribute named 'userID', which represents the value for the primary key of the 'User' in the API the application is communicating with. When the user's projects are loaded from the '/projects' endpoint, the user ID is sent down in the JSON representation of the Project objects as a numeric value. In order to establish a connection for the 'projects' relationship between the 'User' and 'Project' entities, we could add the connection like so: + + // JSON looks like {"project": { "name": "Project Name", "userID": 1234, "projectID": 1 } } + RKEntityMapping *mapping = [RKEntityMapping mappingForEntityForName:@"Project" inManagedObjectStore:managedObjectStore]; + [mapping addAttributeMappingsFromArray:@[ @"name", @"userID", @"projectID" ]]; + + // Find a 'User' whose value for the 'userID' object is equal to the value stored on the 'userID' attribute of the 'Project' and assign it to the relationship + // In other words, "Find the User whose userID == 1234 and assign that object to the 'user' relationship" + [mapping addConnectionForRelationship:@"user" connectedBy:@"userID"]; + + When the connection is attempted to be established by an instance of `RKRelationshipConnectionOperation`, the value for the 'userID' attribute will be read from the Project (in this case, @1234) and the managed object context will be searched for a managed object for the 'User' entity with a corresponding value for its 'userID' attribute. + + When the `connectionSpecifier` is an `NSArray` object, it is interpretted as containing the names of attributes in the specified relationship's entity. Just as with a stirng value, the corresponding destination attributes are determined by invoking the source to destination key transformation block or they are assumed to have matching names. + + When the `connectionSpecifier` is an `NSDictionary` object, the keys are interpretted as containing the names of attributes on the source entity the values are interpretted as the names of attributes on the destination entity. For example: + + // Find the User whose userID is equal to the value stored on the 'createdByUserID' attribute + [mapping addConnectionForRelationship:@"createdByUser" connectedBy:@{ @"createdByUserID": @"userID" }]; + + @param relationshipOrName The relationship object or name of the relationship object that is to be connected. + @param connectionSpecifier An `NSString`, `NSArray`, or `NSDictionary` object specifying how the relationship is to be connected by matching attributes. + @see `RKConnectionDescription` + @see `[RKObjectMapping setSourceToDestinationKeyTransformationBlock:]` + */ +- (void)addConnectionForRelationship:(id)relationshipOrName connectedBy:(id)connectionSpecifier; + +/** + Returns the connection for the specified relationship. + + @param relationshipOrName The relationship object or name of the relationship object for which to retrieve the connection. + @return The connection object for the specified relationship or `nil` if none is configured. + */ +- (RKConnectionDescription *)connectionForRelationship:(id)relationshipOrName; + +///----------------------------- +/// @name Configuring Validation +///----------------------------- + +/** + A Boolean value that determines if newly created `NSManagedObject` instances mapped with the receiver should be discarded when they fail `validateForInsert:`. + + This property allows for the deletion of managed objects that fail validation such that `NSManagedObjectContext` save will complete successfully. Typically an invalid managed object in the graph will result in a failure to save the `NSManagedObjectContext` due to an NSValidation error. In some cases it is desirable to persist only the subset of objects that pass validation and discard the invalid content rather than failing the entire operation. Setting this property to `YES` will result in the deletion of in any newly created `NSManagedObject` instances that fail to return `YES` when sent the `validateForInsert:` message. + + **Default**: `NO` + */ +@property (nonatomic, assign) BOOL discardsInvalidObjectsOnInsert; + +///------------------------------------ +/// @name Flagging Objects for Deletion +///------------------------------------ + +/** + A predicate that identifies objects for the receiver's entity that are to be deleted from the local store. + + This property provides support for local deletion of managed objects mapped as a 'tombstone' record from the source representation. The deletion predicate is used in conjunction with the entity associated with the receiver to construct an `NSFetchRequest` that identifies managed objects that should be deleted when a mapping operation is committed. For example, given the following JSON: + + { "userID": 12345, "is_deleted": true } + + We could map the `is_deleted` key to a Boolean attribute on the model such as `shouldBeDeleted` and configure a deletion predicate using this attribute: + + [entityMapping addAttributeMappingsFromDictionary:@{ @"is_deleted": @"shouldBeDeleted" }]; + entityMapping.deletionPredicate = [NSPredicate predicateWithFormat:@"shouldBeDeleted = true"]; + + When a mapping operation completes, a `NSFetchRequest` will be constructed and executed. Any objects in the store whose `shouldBeDeleted` value is true will be deleted. + */ +@property (nonatomic, copy) NSPredicate *deletionPredicate; + +///------------------------------------------ +/// @name Retrieving Default Attribute Values +///------------------------------------------ + +/** + Returns the default value for the specified attribute as expressed in the Core Data entity definition. This value will + be assigned if the object mapping is applied and a value for a missing attribute is not present in the payload. + */ +- (id)defaultValueForAttribute:(NSString *)attributeName; + +///-------------------------------------------------- +/// @name Configuring Entity Identification Inference +///-------------------------------------------------- + +/** + Enables or disabled entity identification inference. + + **Default:** `YES` + + @param enabled A Boolean value indicating if entity identification inference is to be performed. + */ ++ (void)setEntityIdentificationInferenceEnabled:(BOOL)enabled; + +/** + Returns a Boolean value that indicates if entity identification inference has been enabled. + + @return `YES` if entity identification inference is enabled, else `NO`. + */ ++ (BOOL)isEntityIdentificationInferenceEnabled; + +@end + +/** + The name of a key in the user info dictionary of a `NSEntityDescription` specifying the name or one or more attributes to be used to infer an entity identifier. The value of this string is 'RKEntityIdentificationAttributes'. + */ +extern NSString * const RKEntityIdentificationAttributesUserInfoKey; + +///---------------- +/// @name Functions +///---------------- + +/** + Returns an array of attributes likely to be usable for identification purposes inferred from the given entity. + + Please see the documentation accompanying the `RKEntityMapping` class for details about the inference rules. + + @param entity The entity to infer identification from. + @return An array containing identifying attributes inferred from the given entity or `nil` if none could be inferred. + */ +NSArray *RKIdentificationAttributesInferredFromEntity(NSEntityDescription *entity); + + +@interface RKEntityMapping (Deprecations) +@property (nonatomic, copy) NSString *modificationKey DEPRECATED_ATTRIBUTE_MESSAGE("Use `setModificationAttributeForName:` instead"); +@end diff --git a/Pods/RestKit/Code/CoreData/RKEntityMapping.m b/Pods/RestKit/Code/CoreData/RKEntityMapping.m new file mode 100644 index 0000000..247ee48 --- /dev/null +++ b/Pods/RestKit/Code/CoreData/RKEntityMapping.m @@ -0,0 +1,349 @@ +// +// RKEntityMapping.m +// RestKit +// +// Created by Blake Watters on 5/31/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKEntityMapping.h" +#import "RKManagedObjectStore.h" +#import "RKObjectMappingMatcher.h" +#import "RKPropertyInspector+CoreData.h" +#import "RKLog.h" +#import "RKRelationshipMapping.h" +#import "RKObjectUtilities.h" + +// Set Logging Component +#undef RKLogComponent +#define RKLogComponent RKlcl_cRestKitCoreData + +NSString * const RKEntityIdentificationAttributesUserInfoKey = @"RKEntityIdentificationAttributes"; + +#pragma mark - Functions + +static NSArray *RKEntityIdentificationAttributesFromUserInfoOfEntity(NSEntityDescription *entity) +{ + do { + id userInfoValue = [[entity userInfo] valueForKey:RKEntityIdentificationAttributesUserInfoKey]; + if (userInfoValue) { + NSArray *attributeNames = [userInfoValue isKindOfClass:[NSArray class]] ? userInfoValue : @[ userInfoValue ]; + NSMutableArray *attributes = [NSMutableArray arrayWithCapacity:[attributeNames count]]; + [attributeNames enumerateObjectsUsingBlock:^(NSString *attributeName, NSUInteger idx, BOOL *stop) { + if (! [attributeName isKindOfClass:[NSString class]]) { + [NSException raise:NSInvalidArgumentException format:@"Invalid value given in user info key '%@' of entity '%@': expected an `NSString` or `NSArray` of strings, instead got '%@' (%@)", RKEntityIdentificationAttributesUserInfoKey, [entity name], attributeName, [attributeName class]]; + } + + NSAttributeDescription *attribute = [[entity attributesByName] valueForKey:attributeName]; + if (! attribute) { + [NSException raise:NSInvalidArgumentException format:@"Invalid identifier attribute specified in user info key '%@' of entity '%@': no attribue was found with the name '%@'", RKEntityIdentificationAttributesUserInfoKey, [entity name], attributeName]; + } + + [attributes addObject:attribute]; + }]; + return attributes; + } + entity = [entity superentity]; + } while (entity); + + return nil; +} + +static NSString *RKUnderscoredStringFromCamelCasedString(NSString *camelCasedString) +{ + NSError *error = nil; + NSRegularExpression *regularExpression = [NSRegularExpression regularExpressionWithPattern:@"((^[a-z]+)|([A-Z]{1}[a-z]+)|([A-Z]+(?=([A-Z][a-z])|($))))" options:0 error:&error]; + if (! regularExpression) return nil; + NSMutableArray *lowercasedComponents = [NSMutableArray array]; + [regularExpression enumerateMatchesInString:camelCasedString options:0 range:NSMakeRange(0, [camelCasedString length]) usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) { + [lowercasedComponents addObject:[[camelCasedString substringWithRange:[result range]] lowercaseString]]; + }]; + return [lowercasedComponents componentsJoinedByString:@"_"]; +} + +// Given 'Human', returns 'humanID' and 'human_id'; Given 'AmenityReview' returns 'amenityReviewID' and 'amenity_review_id' +static NSArray *RKEntityIdentificationAttributeNamesForEntity(NSEntityDescription *entity) +{ + NSString *entityName = [entity name]; + NSString *lowerCasedFirstCharacter = [[entityName substringToIndex:1] lowercaseString]; + NSString *camelizedIDAttributeName = [NSString stringWithFormat:@"%@%@ID", lowerCasedFirstCharacter, [entityName substringFromIndex:1]]; + NSString *underscoredIDAttributeName = [NSString stringWithFormat:@"%@_id", RKUnderscoredStringFromCamelCasedString([entity name])]; + return @[ camelizedIDAttributeName, underscoredIDAttributeName ]; +} + +static NSArray *RKEntityIdentificationAttributeNames() +{ + return @[@"identifier", @"id", @"ID", @"URL", @"url"]; +} + +static NSArray *RKArrayOfAttributesForEntityFromAttributesOrNames(NSEntityDescription *entity, NSArray *attributesOrNames) +{ + NSMutableArray *attributes = [NSMutableArray arrayWithCapacity:[attributesOrNames count]]; + for (id attributeOrName in attributesOrNames) { + if ([attributeOrName isKindOfClass:[NSAttributeDescription class]]) { + if (! [[entity properties] containsObject:attributeOrName]) [NSException raise:NSInvalidArgumentException format:@"Invalid attribute value '%@' given for entity identifer: not found in the '%@' entity", attributeOrName, [entity name]]; + [attributes addObject:attributeOrName]; + } else if ([attributeOrName isKindOfClass:[NSString class]]) { + NSAttributeDescription *attribute = [[entity attributesByName] valueForKey:attributeOrName]; + if (!attribute) [NSException raise:NSInvalidArgumentException format:@"Invalid attribute '%@': no attribute was found for the given name in the '%@' entity.", attributeOrName, [entity name]]; + [attributes addObject:attribute]; + } else { + [NSException raise:NSInvalidArgumentException format:@"Invalid value provided for entity identifier attribute: Acceptable values are either `NSAttributeDescription` or `NSString` objects."]; + } + } + + return attributes; +} + +NSArray *RKIdentificationAttributesInferredFromEntity(NSEntityDescription *entity) +{ + NSArray *attributes = RKEntityIdentificationAttributesFromUserInfoOfEntity(entity); + if (attributes) { + return RKArrayOfAttributesForEntityFromAttributesOrNames(entity, attributes); + } + + NSMutableArray *identifyingAttributes = [RKEntityIdentificationAttributeNamesForEntity(entity) mutableCopy]; + [identifyingAttributes addObjectsFromArray:RKEntityIdentificationAttributeNames()]; + for (NSString *attributeName in identifyingAttributes) { + NSAttributeDescription *attribute = [[entity attributesByName] valueForKey:attributeName]; + if (attribute) { + return @[ attribute ]; + } + } + return nil; +} + +static BOOL entityIdentificationInferenceEnabled = YES; + +@interface RKObjectMapping (Private) +- (NSString *)transformSourceKeyPath:(NSString *)keyPath; +@end + +@interface RKObjectMapping () +@property (nonatomic, weak, readwrite) Class objectClass; +@end + +@interface RKEntityMapping () +@property (nonatomic, strong) NSMutableArray *mutableConnections; +@end + +@implementation RKEntityMapping + +@synthesize identificationAttributes = _identificationAttributes; + ++ (instancetype)mappingForClass:(Class)objectClass +{ + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:[NSString stringWithFormat:@"You must provide a managedObjectStore. Invoke mappingForClass:inManagedObjectStore: instead."] + userInfo:nil]; +} + ++ (instancetype)mappingForEntityForName:(NSString *)entityName inManagedObjectStore:(RKManagedObjectStore *)managedObjectStore +{ + NSParameterAssert(entityName); + NSParameterAssert(managedObjectStore); + NSEntityDescription *entity = [managedObjectStore.managedObjectModel entitiesByName][entityName]; + NSAssert(entity, @"Unable to find an Entity with the name '%@' in the managed object model", entityName); + return [[self alloc] initWithEntity:entity]; +} + +- (instancetype)initWithEntity:(NSEntityDescription *)entity +{ + NSAssert(entity, @"Cannot initialize an RKEntityMapping without an entity. Maybe you want RKObjectMapping instead?"); + Class objectClass = NSClassFromString([entity managedObjectClassName]); + NSAssert(objectClass, @"Cannot initialize an entity mapping for an entity with a nil managed object class: Got nil class for managed object class name '%@'. Maybe you forgot to add the class files to your target?", [entity managedObjectClassName]); + self = [self initWithClass:objectClass]; + if (self) { + self.entity = entity; + self.discardsInvalidObjectsOnInsert = NO; + if ([RKEntityMapping isEntityIdentificationInferenceEnabled]) self.identificationAttributes = RKIdentificationAttributesInferredFromEntity(entity); + } + + return self; +} + +- (instancetype)initWithClass:(Class)objectClass +{ + self = [super initWithClass:objectClass]; + if (self) { + self.mutableConnections = [NSMutableArray array]; + } + + return self; +} + +- (id)copyWithZone:(NSZone *)zone +{ + RKEntityMapping *copy = [super copyWithZone:zone]; + copy.entity = self.entity; + copy.identificationAttributes = self.identificationAttributes; + copy.identificationPredicate = self.identificationPredicate; + copy.identificationPredicateBlock = self.identificationPredicateBlock; + copy.deletionPredicate = self.deletionPredicate; + copy.modificationAttribute = self.modificationAttribute; + copy.mutableConnections = [NSMutableArray array]; + + for (RKConnectionDescription *connection in self.connections) { + [copy addConnection:[connection copy]]; + } + + return copy; +} + +- (void)setIdentificationAttributes:(NSArray *)attributesOrNames +{ + if (attributesOrNames && [attributesOrNames count] == 0) [NSException raise:NSInvalidArgumentException format:@"At least one attribute must be provided to identify managed objects"]; + _identificationAttributes = attributesOrNames ? RKArrayOfAttributesForEntityFromAttributesOrNames(self.entity, attributesOrNames) : nil; +} + +- (NSArray *)identificationAttributes +{ + return _identificationAttributes; +} + +- (RKConnectionDescription *)connectionForRelationship:(id)relationshipOrName +{ + if (!([relationshipOrName isKindOfClass:[NSString class]] || [relationshipOrName isKindOfClass:[NSRelationshipDescription class]])) { + [NSException raise:NSInvalidArgumentException format:@"Relationship specifier must be a name or a relationship description"]; + } + NSString *relationshipName = [relationshipOrName isKindOfClass:[NSRelationshipDescription class]] ? [(NSRelationshipDescription *)relationshipOrName name] : relationshipOrName; + for (RKConnectionDescription *connection in self.connections) { + if ([[connection.relationship name] isEqualToString:relationshipName]) { + return connection; + } + } + return nil; +} + +- (void)addConnection:(RKConnectionDescription *)connection +{ + if (! connection) [NSException raise:NSInvalidArgumentException format:@"connection cannot be nil."]; + RKConnectionDescription *existingConnection = [self connectionForRelationship:connection.relationship]; + if (existingConnection) [NSException raise:NSInternalInconsistencyException format:@"Cannot add connection: An existing connection already exists for the '%@' relationship.", connection.relationship.name]; + NSAssert(self.mutableConnections, @"self.mutableConnections should not be nil"); + [self.mutableConnections addObject:connection]; +} + +- (void)removeConnection:(RKConnectionDescription *)connection +{ + [self.mutableConnections removeObject:connection]; +} + +- (NSArray *)connections +{ + return [NSArray arrayWithArray:self.mutableConnections]; +} + +- (void)addConnectionForRelationship:(id)relationshipOrName connectedBy:(id)connectionSpecifier +{ + NSRelationshipDescription *relationship = [relationshipOrName isKindOfClass:[NSRelationshipDescription class]] ? relationshipOrName : [[self.entity relationshipsByName] valueForKey:relationshipOrName]; + NSAssert(relationship, @"No relationship was found named '%@' in the '%@' entity", relationshipOrName, [self.entity name]); + RKConnectionDescription *connection = nil; + if ([connectionSpecifier isKindOfClass:[NSString class]]) { + NSString *sourceAttribute = connectionSpecifier; + NSString *destinationAttribute = [self transformSourceKeyPath:sourceAttribute]; + connection = [[RKConnectionDescription alloc] initWithRelationship:relationship attributes:@{ sourceAttribute: destinationAttribute }]; + } else if ([connectionSpecifier isKindOfClass:[NSArray class]]) { + NSMutableDictionary *attributes = [NSMutableDictionary dictionaryWithCapacity:[connectionSpecifier count]]; + for (NSString *sourceAttribute in connectionSpecifier) { + NSString *destinationAttribute = [self transformSourceKeyPath:sourceAttribute]; + attributes[sourceAttribute] = destinationAttribute; + } + connection = [[RKConnectionDescription alloc] initWithRelationship:relationship attributes:attributes]; + } else if ([connectionSpecifier isKindOfClass:[NSDictionary class]]) { + connection = [[RKConnectionDescription alloc] initWithRelationship:relationship attributes:connectionSpecifier]; + } else { + [NSException raise:NSInvalidArgumentException format:@"Connections can only be described using `NSString`, `NSArray`, or `NSDictionary` objects. Instead, got: %@", connectionSpecifier]; + } + + [self.mutableConnections addObject:connection]; +} + +- (id)defaultValueForAttribute:(NSString *)attributeName +{ + NSAttributeDescription *desc = [[self.entity attributesByName] valueForKey:attributeName]; + return [desc defaultValue]; +} + +- (Class)classForProperty:(NSString *)propertyName +{ + Class propertyClass = [super classForProperty:propertyName]; + if (! propertyClass) { + propertyClass = [[RKPropertyInspector sharedInspector] classForPropertyNamed:propertyName ofEntity:self.entity]; + } + + return propertyClass; +} + +- (Class)classForKeyPath:(NSString *)keyPath +{ + NSArray *components = [keyPath componentsSeparatedByString:@"."]; + Class propertyClass = self.objectClass; + for (NSString *property in components) { + propertyClass = [[RKPropertyInspector sharedInspector] classForPropertyNamed:property ofClass:propertyClass isPrimitive:nil]; + if (! propertyClass) propertyClass = [[RKPropertyInspector sharedInspector] classForPropertyNamed:property ofEntity:self.entity]; + if (! propertyClass) break; + } + + return propertyClass; +} + +- (void)setModificationAttribute:(NSAttributeDescription *)modificationAttribute +{ + if (modificationAttribute && ![self.entity.properties containsObject:modificationAttribute]) [NSException raise:NSInvalidArgumentException format:@"The attribute given is not a property of the '%@' entity.", [self.entity name]]; + _modificationAttribute = modificationAttribute; +} + +- (void)setModificationAttributeForName:(NSString *)attributeName +{ + if (attributeName) { + NSAttributeDescription *attribute = [self.entity attributesByName][attributeName]; + if (!attribute) [NSException raise:NSInvalidArgumentException format:@"No attribute with the name '%@' was found in the '%@' entity.", attributeName, self.entity.name]; + self.modificationAttribute = attribute; + } else { + self.modificationAttribute = nil; + } +} + ++ (void)setEntityIdentificationInferenceEnabled:(BOOL)enabled +{ + entityIdentificationInferenceEnabled = enabled; +} + ++ (BOOL)isEntityIdentificationInferenceEnabled +{ + return entityIdentificationInferenceEnabled; +} + +@end + +@implementation RKEntityMapping (Deprecations) + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-implementations" + +- (NSString *)modificationKey +{ + return self.modificationAttribute.name; +} + +- (void)setModificationKey:(NSString *)modificationKey +{ + [self setModificationAttributeForName:modificationKey]; +} + +#pragma clang diagnostic pop + +@end diff --git a/Pods/RestKit/Code/CoreData/RKFetchRequestManagedObjectCache.h b/Pods/RestKit/Code/CoreData/RKFetchRequestManagedObjectCache.h new file mode 100644 index 0000000..da50ebe --- /dev/null +++ b/Pods/RestKit/Code/CoreData/RKFetchRequestManagedObjectCache.h @@ -0,0 +1,31 @@ +// +// RKFetchRequestManagedObjectCache.h +// RestKit +// +// Created by Jeff Arena on 1/24/12. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKManagedObjectCaching.h" + +/** + Provides a simple managed object cache strategy in which every request for an object + is satisfied by dispatching an NSFetchRequest against the Core Data persistent store. + Performance can be disappointing for data sets with a large amount of redundant data + being mapped and connected together, but the memory footprint stays flat. + */ +@interface RKFetchRequestManagedObjectCache : NSObject + +@end diff --git a/Pods/RestKit/Code/CoreData/RKFetchRequestManagedObjectCache.m b/Pods/RestKit/Code/CoreData/RKFetchRequestManagedObjectCache.m new file mode 100644 index 0000000..3a1d5b6 --- /dev/null +++ b/Pods/RestKit/Code/CoreData/RKFetchRequestManagedObjectCache.m @@ -0,0 +1,129 @@ +// +// RKFetchRequestManagedObjectCache.m +// RestKit +// +// Created by Jeff Arena on 1/24/12. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKFetchRequestManagedObjectCache.h" +#import "RKLog.h" +#import "RKPropertyInspector.h" +#import "RKPropertyInspector+CoreData.h" +#import "RKObjectUtilities.h" + +// Set Logging Component +#undef RKLogComponent +#define RKLogComponent RKlcl_cRestKitCoreData + +/* + This function computes a cache key given a dictionary of attribute values. Each attribute name is used as a fragment within the aggregate cache key. A suffix qualifier is appended that differentiates singular vs. collection attribute values so that '==' and 'IN' predicates are computed appropriately. + */ +static NSString *RKPredicateCacheKeyForAttributeValues(NSDictionary *attributesValues) +{ + NSArray *sortedKeys = [[attributesValues allKeys] sortedArrayUsingSelector:@selector(compare:)]; + NSMutableArray *keyFragments = [NSMutableArray array]; + for (NSString *attributeName in sortedKeys) { + id value = attributesValues[attributeName]; + NSString *suffix = [value respondsToSelector:@selector(count)] ? @"+" : @"."; + [keyFragments addObject:[attributeName stringByAppendingString:suffix]]; + } + return [keyFragments componentsJoinedByString:@":"]; +} + +// NOTE: We build a dynamic format string here because `NSCompoundPredicate` does not support use of substiution variables +static NSPredicate *RKPredicateWithSubsitutionVariablesForAttributeValues(NSDictionary *attributeValues) +{ + NSArray *attributeNames = [attributeValues allKeys]; + NSMutableArray *formatFragments = [NSMutableArray arrayWithCapacity:[attributeNames count]]; + [attributeValues enumerateKeysAndObjectsUsingBlock:^(NSString *attributeName, id value, BOOL *stop) { + NSString *formatFragment = RKObjectIsCollection(value) + ? [NSString stringWithFormat:@"%@ IN $%@", attributeName, attributeName] + : [NSString stringWithFormat:@"%@ = $%@", attributeName, attributeName]; + [formatFragments addObject:formatFragment]; + }]; + + return [NSPredicate predicateWithFormat:[formatFragments componentsJoinedByString:@" AND "]]; +} + +@interface RKFetchRequestManagedObjectCache () +@property (nonatomic, strong) NSMutableDictionary *predicateCache; +#if OS_OBJECT_USE_OBJC +@property (nonatomic, strong) dispatch_queue_t cacheQueue; +#else +@property (nonatomic, assign) dispatch_queue_t cacheQueue; +#endif +@end + +@implementation RKFetchRequestManagedObjectCache + +- (instancetype)init +{ + self = [super init]; + if (self) { + self.predicateCache = [NSMutableDictionary dictionary]; + self.cacheQueue = dispatch_queue_create("org.restkit.core-data.fetch-request-cache-queue", DISPATCH_QUEUE_CONCURRENT); + } + return self; +} + +- (void)dealloc +{ +#if !OS_OBJECT_USE_OBJC + if (_cacheQueue) dispatch_release(_cacheQueue); +#endif + _cacheQueue = NULL; +} + +- (NSSet *)managedObjectsWithEntity:(NSEntityDescription *)entity + attributeValues:(NSDictionary *)attributeValues + inManagedObjectContext:(NSManagedObjectContext *)managedObjectContext +{ + NSAssert(entity, @"Cannot find existing managed object without a target class"); + NSAssert(attributeValues, @"Cannot retrieve cached objects without attribute values to identify them with."); + NSAssert(managedObjectContext, @"Cannot find existing managed object with a nil context"); + + if ([attributeValues count] == 0) return [NSSet set]; + + NSString *predicateCacheKey = RKPredicateCacheKeyForAttributeValues(attributeValues); + + __block NSPredicate *substitutionPredicate; + dispatch_sync(self.cacheQueue, ^{ + substitutionPredicate = (self.predicateCache)[predicateCacheKey]; + }); + + if (! substitutionPredicate) { + substitutionPredicate = RKPredicateWithSubsitutionVariablesForAttributeValues(attributeValues); + dispatch_barrier_async(self.cacheQueue, ^{ + (self.predicateCache)[predicateCacheKey] = substitutionPredicate; + }); + } + + NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:[entity name]]; + fetchRequest.predicate = [substitutionPredicate predicateWithSubstitutionVariables:attributeValues]; + __block NSError *error = nil; + __block NSArray *objects = nil; + [managedObjectContext performBlockAndWait:^{ + objects = [managedObjectContext executeFetchRequest:fetchRequest error:&error]; + }]; + if (! objects) { + RKLogError(@"Failed to execute fetch request due to error: %@", error); + } + RKLogDebug(@"Found objects '%@' using fetchRequest '%@'", objects, fetchRequest); + + return [NSSet setWithArray:objects]; +} + +@end diff --git a/Pods/RestKit/Code/CoreData/RKInMemoryManagedObjectCache.h b/Pods/RestKit/Code/CoreData/RKInMemoryManagedObjectCache.h new file mode 100644 index 0000000..0991690 --- /dev/null +++ b/Pods/RestKit/Code/CoreData/RKInMemoryManagedObjectCache.h @@ -0,0 +1,42 @@ +// +// RKInMemoryManagedObjectCache.h +// RestKit +// +// Created by Jeff Arena on 1/24/12. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKManagedObjectCaching.h" + +/** + Provides a fast managed object cache where-in object instances are retained in memory to avoid hitting the Core Data persistent store. Performance is greatly increased over fetch request based strategy at the expense of memory consumption. + */ +@interface RKInMemoryManagedObjectCache : NSObject + +- (instancetype)init __attribute__((unavailable("Invoke initWithManagedObjectContext: instead."))); + +///--------------------------- +/// @name Initializing a Cache +///--------------------------- + +/** + Initializes the receiver with a managed object context that is to be observed and used to populate the in memory cache. The receiver may then be used to fulfill cache requests for child contexts of the given managed object context. + + @param managedObjectContext The managed object context with which to initialize the receiver. + @return The receiver, initialized with the given managed object context. + */ +- (instancetype)initWithManagedObjectContext:(NSManagedObjectContext *)managedObjectContext NS_DESIGNATED_INITIALIZER; + +@end diff --git a/Pods/RestKit/Code/CoreData/RKInMemoryManagedObjectCache.m b/Pods/RestKit/Code/CoreData/RKInMemoryManagedObjectCache.m new file mode 100644 index 0000000..e41857b --- /dev/null +++ b/Pods/RestKit/Code/CoreData/RKInMemoryManagedObjectCache.m @@ -0,0 +1,164 @@ +// +// RKInMemoryManagedObjectCache.m +// RestKit +// +// Created by Jeff Arena on 1/24/12. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKInMemoryManagedObjectCache.h" +#import "RKEntityCache.h" +#import "RKLog.h" +#import "RKEntityByAttributeCache.h" + +// Set Logging Component +#undef RKLogComponent +#define RKLogComponent RKlcl_cRestKitCoreData + +static NSPersistentStoreCoordinator *RKPersistentStoreCoordinatorFromManagedObjectContext(NSManagedObjectContext *managedObjectContext) +{ + NSManagedObjectContext *currentContext = managedObjectContext; + do { + if ([currentContext persistentStoreCoordinator]) return [currentContext persistentStoreCoordinator]; + currentContext = [currentContext parentContext]; + } while (currentContext); + return nil; +} + +static dispatch_queue_t RKInMemoryManagedObjectCacheCallbackQueue(void) +{ + static dispatch_once_t onceToken; + static dispatch_queue_t callbackQueue; + dispatch_once(&onceToken, ^{ + callbackQueue = dispatch_queue_create("org.restkit.core-data.in-memory-cache.callback-queue", DISPATCH_QUEUE_CONCURRENT); + }); + return callbackQueue; +} + +@interface RKInMemoryManagedObjectCache () +@property (nonatomic, strong, readwrite) RKEntityCache *entityCache; +@property (nonatomic, assign) dispatch_queue_t callbackQueue; +@end + +@implementation RKInMemoryManagedObjectCache + +- (instancetype)initWithManagedObjectContext:(NSManagedObjectContext *)managedObjectContext +{ + self = [super init]; + if (self) { + NSManagedObjectContext *cacheContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]; + [cacheContext setPersistentStoreCoordinator:RKPersistentStoreCoordinatorFromManagedObjectContext(managedObjectContext)]; + self.entityCache = [[RKEntityCache alloc] initWithManagedObjectContext:cacheContext]; + self.entityCache.callbackQueue = RKInMemoryManagedObjectCacheCallbackQueue(); + + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleManagedObjectContextDidChangeNotification:) name:NSManagedObjectContextObjectsDidChangeNotification object:managedObjectContext]; + } + return self; +} + +- (instancetype)init +{ + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:[NSString stringWithFormat:@"%@ Failed to call designated initializer. Invoke initWithManagedObjectContext: instead.", + NSStringFromClass([self class])] + userInfo:nil]; +} + +- (void)dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + +- (NSSet *)managedObjectsWithEntity:(NSEntityDescription *)entity + attributeValues:(NSDictionary *)attributeValues + inManagedObjectContext:(NSManagedObjectContext *)managedObjectContext +{ + NSParameterAssert(entity); + NSParameterAssert(attributeValues); + NSParameterAssert(managedObjectContext); + + NSArray *attributes = [attributeValues allKeys]; + if (! [self.entityCache isEntity:entity cachedByAttributes:attributes]) { + RKLogInfo(@"Caching instances of Entity '%@' by attributes '%@'", entity.name, [attributes componentsJoinedByString:@", "]); + dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); + [self.entityCache cacheObjectsForEntity:entity byAttributes:attributes completion:^{ + dispatch_semaphore_signal(semaphore); + }]; + dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); + + RKEntityByAttributeCache *attributeCache = [self.entityCache attributeCacheForEntity:entity attributes:attributes]; + + // Fetch any pending objects and add them to the cache + NSFetchRequest *fetchRequest = [NSFetchRequest new]; + fetchRequest.entity = entity; + fetchRequest.includesPendingChanges = YES; + + [managedObjectContext performBlockAndWait:^{ + NSError *error = nil; + NSArray *objects = nil; + objects = [managedObjectContext executeFetchRequest:fetchRequest error:&error]; + if (objects) { + [attributeCache addObjects:[NSSet setWithArray:objects] completion:^{ + dispatch_semaphore_signal(semaphore); + }]; + } else { + RKLogError(@"Fetched pre-loading existing managed objects with error: %@", error); + dispatch_semaphore_signal(semaphore); + } + }]; + dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); + +#if !OS_OBJECT_USE_OBJC + dispatch_release(semaphore); +#endif + + RKLogTrace(@"Cached %ld objects", (long)[attributeCache count]); + } + + return [self.entityCache objectsForEntity:entity withAttributeValues:attributeValues inContext:managedObjectContext]; +} + +- (void)didFetchObject:(NSManagedObject *)object +{ + [self.entityCache addObjects:[NSSet setWithObject:object] completion:nil]; +} + +- (void)didCreateObject:(NSManagedObject *)object +{ + [self.entityCache addObjects:[NSSet setWithObject:object] completion:nil]; +} + +- (void)didDeleteObject:(NSManagedObject *)object +{ + [self.entityCache removeObjects:[NSSet setWithObject:object] completion:nil]; +} + +- (void)handleManagedObjectContextDidChangeNotification:(NSNotification *)notification +{ + // Observe the parent context for changes and update the caches + NSDictionary *userInfo = notification.userInfo; + NSSet *insertedObjects = userInfo[NSInsertedObjectsKey]; + NSSet *updatedObjects = userInfo[NSUpdatedObjectsKey]; + NSSet *deletedObjects = userInfo[NSDeletedObjectsKey]; + RKLogTrace(@"insertedObjects=%@, updatedObjects=%@, deletedObjects=%@", insertedObjects, updatedObjects, deletedObjects); + + NSMutableSet *objectsToAdd = [NSMutableSet setWithSet:insertedObjects]; + [objectsToAdd unionSet:updatedObjects]; + + [self.entityCache addObjects:objectsToAdd completion:nil]; + [self.entityCache removeObjects:deletedObjects completion:nil]; +} + +@end diff --git a/Pods/RestKit/Code/CoreData/RKManagedObjectCaching.h b/Pods/RestKit/Code/CoreData/RKManagedObjectCaching.h new file mode 100644 index 0000000..2fcfcad --- /dev/null +++ b/Pods/RestKit/Code/CoreData/RKManagedObjectCaching.h @@ -0,0 +1,72 @@ +// +// RKManagedObjectCaching.h +// RestKit +// +// Created by Jeff Arena on 1/24/12. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import + +/** + Objects implementing the `RKManagedObjectCaching` provide support for retrieving managed object matching a set of attributes using an opaque caching strategy. The objects retrieved are not required to be in any particular order, but must exactly match the attribute values requested. + */ +@protocol RKManagedObjectCaching + +@required + +///--------------------------------- +/// @name Retrieving Managed Objects +///--------------------------------- + +/** + Returns all managed objects for a given entity with attributes whose names and values match the given dictionary in a given context. + + @param entity The entity to retrieve managed objects for. + @param attributeValues A dictionary specifying the attribute criteria for retrieving managed objects. + @param managedObjectContext The context to fetch the matching objects in. + */ +- (NSSet *)managedObjectsWithEntity:(NSEntityDescription *)entity + attributeValues:(NSDictionary *)attributeValues + inManagedObjectContext:(NSManagedObjectContext *)managedObjectContext; + +///--------------------------------------------------- +/// @name Handling Managed Object Change Notifications +///--------------------------------------------------- + +@optional + +/** + Invoked to inform the receiver that an object was fetched and should be added to the cache. + + @param object The object that was fetched from a managed object context. + */ +- (void)didFetchObject:(NSManagedObject *)object; + +/** + Invoked to inform the receiver that an object was created and should be added to the cache. + + @param object The object that was created in a managed object context. + */ +- (void)didCreateObject:(NSManagedObject *)object; + +/** + Invoked to inform the receiver that an object was deleted and should be removed to the cache. + + @param object The object that was deleted from a managed object context. + */ +- (void)didDeleteObject:(NSManagedObject *)object; + +@end diff --git a/Pods/RestKit/Code/CoreData/RKManagedObjectImporter.h b/Pods/RestKit/Code/CoreData/RKManagedObjectImporter.h new file mode 100644 index 0000000..84d3a32 --- /dev/null +++ b/Pods/RestKit/Code/CoreData/RKManagedObjectImporter.h @@ -0,0 +1,158 @@ +// +// RKManagedObjectImporter.h +// RestKit +// +// Created by Blake Watters on 3/4/10. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import + +@class RKMapping, RKObjectManager; +@protocol RKManagedObjectCaching; + +/** + Instances of `RKManagedObjectImporter` perform bulk imports of managed objects into a persistent store from source files (typically in JSON or XML format) using object mappings. The importer provides functionality for updating an existing persistent store or creating a seed database that can be used to bootstrap a new persistent store with an initial data set. + + The importer requires that the source files have a MIME type that is identifiable by file extension and be parsable using a parser registered with the shared parser registry. + + @see RKMIMETypeSerialization + */ +@interface RKManagedObjectImporter : NSObject + +- (instancetype)init __attribute__((unavailable("Invoke initWithManagedObjectModel:storePath: instead."))); + +///------------------------------- +/// @name Initializing an Importer +///------------------------------- + +/** + Initializes the receiver with a given managed object model and a path at which a SQLite persistent store + should be created to persist imported managed objects. + + When initialized with a managed object model and store path, the receiver will construct an internal + persistent store coordinator, SQLite persistent store, and managed object context with the private queue + concurrency type with which to perform the importing. + + @param managedObjectModel A Core Data manage object model with which to initialize the receiver. + @param storePath The path at which to create a SQLite persistent store to persist the imported managed objects. + @return The receiver, initialized with the given managed object model and a complete Core Data persistence + stack with a SQLite persistent store at the given store path. + + @warning As this initialization code path is typical for generating seed databases, the value of + `resetsStoreBeforeImporting` is initialized to **YES**. + */ +- (instancetype)initWithManagedObjectModel:(NSManagedObjectModel *)managedObjectModel storePath:(NSString *)storePath NS_DESIGNATED_INITIALIZER; + +/** + Initializes the receiver with a given persistent store in which to persist imported managed objects. + + When initialized with a persistent store, the receiver will construct a managed object context with the + private queue concurrency type and the persistent store coordinator of the given persistent store. This + prepares the receiver for importing content into an existing Core Data persistence stack. + + @param persistentStore A Core Data persistent store with which to initialize the receiver. + @return The receiver, initialized with the given persistent store. The persistent store coordinator and + managed object model are determined from the given persistent store and a new managed object context with + the private queue concurrency type is constructed. + */ +- (instancetype)initWithPersistentStore:(NSPersistentStore *)persistentStore NS_DESIGNATED_INITIALIZER; + +/** + A Boolean value indicating whether existing managed objects in the persistent store should + be deleted before import. + + The default value of this property is YES if the receiver was initialized with a + managed object model and store path, else NO. + */ +@property (nonatomic, assign) BOOL resetsStoreBeforeImporting; + +///---------------------------------- +/// @name Accessing Core Data Details +///---------------------------------- + +/** + The persistent store in which imported managed objects will be persisted. + */ +@property (nonatomic, strong, readonly) NSPersistentStore *persistentStore; + +/** + The managed object model containing entities that may be imported by the receiver. + */ +@property (nonatomic, strong, readonly) NSManagedObjectModel *managedObjectModel; + +/** + A managed object context with the NSPrivateQueueConcurrencyType concurrency type + used to perform the import. + */ +@property (nonatomic, strong, readonly) NSManagedObjectContext *managedObjectContext; + +/** + A convenience accessor for retrieving the complete filesystem path to the persistent + store in which the receiver will persist imported managed objects. + + Equivalent to executing the following example code: + + NSURL *URL = [importer.persistentStore.persistentStoreCoordinator URLForPersistentStore:importer.persistentStore]; + return [URL path]; + + */ +@property (nonatomic, strong, readonly) NSString *storePath; + +/** + A class that conforms to the `RKManagedObjectCaching` protocol that should be used when performing the import. + + **Default**: An instance of `RKInMemoryManagedObjectCache`. + */ +@property (nonatomic, strong) id managedObjectCache; + +///----------------------------------------------------------------------------- +/// @name Importing Managed Objects +///----------------------------------------------------------------------------- + +/** + Imports managed objects from the file or directory at the given path. + + @param path The path to the file or directory you wish to import. This parameter must not be nil. + @param mapping The entity or dynamic mapping you wish to use for importing content at the given path. + @param keyPath An optional key path to be evaluated against the results of parsing the content read at the given path. If the + mappable content is not contained in a nesting attribute, the key path should be specified as nil. + @param error On input, a pointer to an error object. If an error occurs, this pointer is set to an actual error object containing + the error information. You may specify nil for this parameter if you do not want the error information. + @return A count of the number of managed object imported from the given path or NSNotFound if an error occurred during import. + */ +- (NSUInteger)importObjectsFromItemAtPath:(NSString *)path withMapping:(RKMapping *)mapping keyPath:(NSString *)keyPath error:(NSError **)error; + +/** + Finishes the import process by saving the managed object context to the persistent store, ensuring all + imported managed objects are written to disk. + + @param error On input, a pointer to an error object. If an error occurs, this pointer is set to an actual error object containing + the error information. You may specify nil for this parameter if you do not want the error information. + @return YES if the save to the persistent store was successful, else NO. + */ +- (BOOL)finishImporting:(NSError **)error; + +///----------------------------------------------------------------------------- +/// @name Obtaining Seeding Info +///----------------------------------------------------------------------------- + +/** + Logs information about where on the filesystem to access the SQLite database for the persistent + store in which the imported managed objects were persisted. + */ +- (void)logSeedingInfo; + +@end diff --git a/Pods/RestKit/Code/CoreData/RKManagedObjectImporter.m b/Pods/RestKit/Code/CoreData/RKManagedObjectImporter.m new file mode 100644 index 0000000..65213b7 --- /dev/null +++ b/Pods/RestKit/Code/CoreData/RKManagedObjectImporter.m @@ -0,0 +1,298 @@ +// +// RKManagedObjectImporter.m +// RestKit +// +// Created by Blake Watters on 3/4/10. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#if TARGET_OS_IPHONE +#import +#endif + +#import "RKManagedObjectImporter.h" +#import "RKMapperOperation.h" +#import "RKManagedObjectMappingOperationDataSource.h" +#import "RKInMemoryManagedObjectCache.h" +#import "RKFetchRequestManagedObjectCache.h" +#import "RKMIMETypeSerialization.h" +#import "RKPathUtilities.h" +#import "RKLog.h" + +// Set Logging Component +#undef RKLogComponent +#define RKLogComponent RKlcl_cRestKitCoreData + +@interface RKManagedObjectImporter () +@property (nonatomic, strong, readwrite) NSManagedObjectModel *managedObjectModel; +@property (nonatomic, strong, readwrite) NSString *storePath; +@property (nonatomic, strong, readwrite) NSPersistentStoreCoordinator *persistentStoreCoordinator; +@property (nonatomic, strong, readwrite) NSPersistentStore *persistentStore; +@property (nonatomic, strong, readwrite) NSManagedObjectContext *managedObjectContext; +@property (nonatomic, strong, readwrite) RKManagedObjectMappingOperationDataSource *mappingOperationDataSource; +@property (nonatomic, strong, readwrite) NSOperationQueue *connectionQueue; +@property (nonatomic, assign) BOOL hasPerformedResetIfNecessary; +@end + +@implementation RKManagedObjectImporter + +- (instancetype)initWithManagedObjectModel:(NSManagedObjectModel *)managedObjectModel storePath:(NSString *)storePath +{ + NSParameterAssert(managedObjectModel); + NSParameterAssert(storePath); + + self = [super init]; + if (self) { + self.managedObjectModel = managedObjectModel; + self.storePath = storePath; + + NSError *error = nil; + NSPersistentStoreCoordinator *persistentStoreCoordinator = [self createPersistentStoreCoordinator:&error]; + NSAssert(persistentStoreCoordinator, @"Importer initialization failed: Unable to create persistent store coordinator: %@", error); + self.persistentStoreCoordinator = persistentStoreCoordinator; + + NSManagedObjectContext *managedObjectContext = [self createManagedObjectContext]; + NSAssert(managedObjectContext, @"Importer initialization failed: Unable to create managed object context"); + self.managedObjectContext = managedObjectContext; + + self.connectionQueue = [NSOperationQueue new]; + [self.connectionQueue setName:@"RKManagedObjectImporter Connection Queue"]; + [self.connectionQueue setSuspended:YES]; + + self.managedObjectCache = [[RKInMemoryManagedObjectCache alloc] initWithManagedObjectContext:managedObjectContext]; + + self.hasPerformedResetIfNecessary = NO; + self.resetsStoreBeforeImporting = YES; + } + + return self; +} + +- (instancetype)initWithPersistentStore:(NSPersistentStore *)persistentStore +{ + NSParameterAssert(persistentStore); + + self = [super init]; + if (self) { + self.persistentStoreCoordinator = persistentStore.persistentStoreCoordinator; + self.managedObjectModel = persistentStore.persistentStoreCoordinator.managedObjectModel; + + NSURL *storeURL = [self.persistentStoreCoordinator URLForPersistentStore:persistentStore]; + self.storePath = [storeURL path]; + + NSManagedObjectContext *managedObjectContext = [self createManagedObjectContext]; + NSAssert(managedObjectContext, @"Importer initialization failed: Unable to create managed object store"); + self.managedObjectContext = managedObjectContext; + + self.connectionQueue = [NSOperationQueue new]; + [self.connectionQueue setName:@"RKManagedObjectImporter Connection Queue"]; + [self.connectionQueue setSuspended:YES]; + + self.managedObjectCache = [[RKInMemoryManagedObjectCache alloc] initWithManagedObjectContext:managedObjectContext]; + + self.hasPerformedResetIfNecessary = NO; + self.resetsStoreBeforeImporting = NO; + } + + return self; +} + +- (instancetype)init +{ + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:[NSString stringWithFormat:@"%@ Failed to call designated initializer. Invoke initWithManagedObjectModel:storePath: instead.", + NSStringFromClass([self class])] + userInfo:nil]; +} + +- (NSPersistentStoreCoordinator *)createPersistentStoreCoordinator:(NSError **)error +{ + BOOL isDirectory = NO; + [[NSFileManager defaultManager] fileExistsAtPath:self.storePath isDirectory:&isDirectory]; + NSAssert(!isDirectory, @"Cannot create SQLite persistent store: The given store path specifies a directory."); + + NSURL *storeURL = [NSURL fileURLWithPath:self.storePath]; + NSPersistentStoreCoordinator *persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:self.managedObjectModel]; + NSPersistentStore *persistentStore = [persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType + configuration:nil + URL:storeURL + options:nil error:error]; + if (! persistentStore) { + return nil; + } + + return persistentStoreCoordinator; +} + +- (NSManagedObjectContext *)createManagedObjectContext +{ + NSManagedObjectContext *managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]; + [managedObjectContext performBlockAndWait:^{ + managedObjectContext.persistentStoreCoordinator = self.persistentStoreCoordinator; + managedObjectContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy; + }]; + + return managedObjectContext; +} + +- (void)setManagedObjectCache:(id)managedObjectCache +{ + NSAssert(self.connectionQueue, @"Connection Queue cannot be nil"); + self.mappingOperationDataSource = [[RKManagedObjectMappingOperationDataSource alloc] initWithManagedObjectContext:self.managedObjectContext + cache:managedObjectCache]; + self.mappingOperationDataSource.operationQueue = self.connectionQueue; +} + +- (void)resetPersistentStoreIfNecessary +{ + if (self.hasPerformedResetIfNecessary) return; + + if (self.resetsStoreBeforeImporting) { + RKLogInfo(@"Persistent store reset requested before importing. Deleting existing managed object instances..."); + for (NSEntityDescription *entity in self.managedObjectModel.entities) { + @autoreleasepool { + NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; + fetchRequest.entity = entity; + [self.managedObjectContext performBlockAndWait:^{ + NSError *error; + NSArray *managedObjects = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error]; + RKLogInfo(@"Deleting %ld managed object instances for the '%@' entity", (unsigned long) [managedObjects count], entity.name); + for (NSManagedObject *managedObject in managedObjects) { + [self.managedObjectContext deleteObject:managedObject]; + } + }]; + } + } + } + + self.hasPerformedResetIfNecessary = YES; +} + +- (NSUInteger)importObjectsFromFileAtPath:(NSString *)path withMapping:(RKMapping *)mapping keyPath:(NSString *)keyPath error:(NSError **)error +{ + NSParameterAssert(path); + NSParameterAssert(mapping); + + // Perform the reset on the first import action if requested + [self resetPersistentStoreIfNecessary]; + + __block NSError *localError = nil; + NSData *payload = [NSData dataWithContentsOfFile:path options:0 error:&localError]; + if (! payload) { + RKLogError(@"Failed to read file at path '%@': %@", path, [localError localizedDescription]); + if (error) *error = localError; + return NSNotFound; + } + + NSString *MIMEType = RKMIMETypeFromPathExtension(path); + id parsedData = [RKMIMETypeSerialization objectFromData:payload MIMEType:MIMEType error:&localError]; + if (!parsedData) { + RKLogError(@"Failed to parse file at path '%@': %@", path, [localError localizedDescription]); + } + + if (! parsedData) { + if (error) *error = localError; + return NSNotFound; + } + + NSDictionary *mappingDictionary = @{ (keyPath ?: [NSNull null]) : mapping }; + RKMapperOperation *mapper = [[RKMapperOperation alloc] initWithRepresentation:parsedData mappingsDictionary:mappingDictionary]; + mapper.mappingOperationDataSource = self.mappingOperationDataSource; + __block RKMappingResult *mappingResult; + [self.managedObjectContext performBlockAndWait:^{ + [mapper start]; + mappingResult = mapper.mappingResult; + localError = mapper.error; + }]; + if (mappingResult == nil) { + if (error) *error = localError; + RKLogError(@"Importing file at path '%@' failed with error: %@", path, localError); + return NSNotFound; + } + + NSUInteger objectCount = [mappingResult count]; + RKLogInfo(@"Imported %lu objects from file at path '%@'", (unsigned long)objectCount, path); + return objectCount; +} + +- (NSUInteger)importObjectsFromDirectoryAtPath:(NSString *)path withMapping:(RKMapping *)mapping keyPath:(NSString *)keyPath error:(NSError **)error +{ + NSError *localError = nil; + NSArray *entries = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:path error:&localError]; + if (! entries) { + RKLogError(@"Import failed for directory at path '%@': Unable to read directory contents with error: %@", path, localError); + if (error) *error = localError; + return NSNotFound; + } + + NSUInteger aggregateObjectCount = 0; + for (NSString *entry in entries) { + NSUInteger objectCount = [self importObjectsFromFileAtPath:[path stringByAppendingPathComponent:entry] withMapping:mapping keyPath:keyPath error:&localError]; + if (objectCount == NSNotFound) { + if (error) *error = localError; + return NSNotFound; + } else { + aggregateObjectCount += objectCount; + } + } + + return aggregateObjectCount; +} + +- (NSUInteger)importObjectsFromItemAtPath:(NSString *)path withMapping:(RKMapping *)mapping keyPath:(NSString *)keyPath error:(NSError **)error +{ + NSParameterAssert(path); + NSParameterAssert(mapping); + + BOOL isDirectory; + [[NSFileManager defaultManager] fileExistsAtPath:path isDirectory:&isDirectory]; + if (isDirectory) { + return [self importObjectsFromDirectoryAtPath:path withMapping:mapping keyPath:keyPath error:error]; + } + + return [self importObjectsFromFileAtPath:path withMapping:mapping keyPath:keyPath error:error]; +} + +- (BOOL)finishImporting:(NSError **)error +{ + // Perform our connection operations in a batch, before we save the MOC + RKLogInfo(@"Starting %lu connection operations...", (unsigned long) self.connectionQueue.operationCount); + [self.connectionQueue setMaxConcurrentOperationCount:50]; + [self.connectionQueue setSuspended:NO]; + [self.connectionQueue waitUntilAllOperationsAreFinished]; + + __block BOOL success; + __block NSError *localError = nil; + [self.managedObjectContext performBlockAndWait:^{ + success = [self.managedObjectContext save:&localError]; + if (! success) { + RKLogCoreDataError(localError); + } + }]; + + if (! success && error) *error = localError; + return success; +} + +- (void)logSeedingInfo +{ + NSString *storeDirectory = [self.storePath stringByDeletingLastPathComponent]; + NSString *storeFilename = [self.storePath lastPathComponent]; + RKLogCritical(@"A seed database has been generated at '%@'. " + @"Please execute `open \"%@\"` in your Terminal and copy %@ to your app. Be sure to add the seed database to your \"Copy Resources\" build phase.", + self.storePath, storeDirectory, storeFilename); +} + +@end diff --git a/Pods/RestKit/Code/CoreData/RKManagedObjectMappingOperationDataSource.h b/Pods/RestKit/Code/CoreData/RKManagedObjectMappingOperationDataSource.h new file mode 100644 index 0000000..9f8c19d --- /dev/null +++ b/Pods/RestKit/Code/CoreData/RKManagedObjectMappingOperationDataSource.h @@ -0,0 +1,84 @@ +// +// RKManagedObjectMappingOperationDataSource.h +// RestKit +// +// Created by Blake Watters on 7/3/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import +#import "RKMappingOperationDataSource.h" + +@protocol RKManagedObjectCaching; + +/** + The `RKManagedObjectMappingOperationDataSource` class provides support for performing object mapping operations where the mapped objects exist within a Core Data managed object context. The class is responsible for finding exist managed object instances by the identification attributes, instantiating new managed objects, and connecting relationships for mapped objects. + + @see `RKMappingOperationDataSource` + @see `RKConnectionMapping` + */ +@interface RKManagedObjectMappingOperationDataSource : NSObject + +///------------------------------------------------------------------ +/// @name Initializing a Managed Object Mapping Operation Data Source +///------------------------------------------------------------------ + +/** + Initializes the receiver with a given managed object context and managed object cache. + + @param managedObjectContext The managed object context with which to associate the receiver. Cannot be nil. + @param managedObjectCache The managed object cache used by the receiver to find existing object instances by their identification attributes. + @return The receiver, initialized with the given managed object context and managed objet cache. + */ +- (instancetype)initWithManagedObjectContext:(NSManagedObjectContext *)managedObjectContext cache:(id)managedObjectCache; + +///----------------------------------------------------- +/// @name Accessing the Managed Object Context and Cache +///----------------------------------------------------- + +/** + The managed object context with which the receiver is associated. + */ +@property (nonatomic, strong, readonly) NSManagedObjectContext *managedObjectContext; + +/** + The managed object cache utilized by the receiver to find existing managed object instances by the identification attributes. A nil managed object cache will result in the insertion of new managed objects for all mapped content. + + @see `RKFetchRequestManagedObjectCache` + @see `RKInMemoryManagedObjectCache` + */ +@property (nonatomic, strong, readonly) id managedObjectCache; + +///--------------------------------------------------- +/// @name Configuring Relationship Connection Queueing +///--------------------------------------------------- + +/** + The parent operation upon which instances of `RKRelationshipConnectionOperation` created by the data source are dependent upon. + + When connecting relationships as part of a managed object mapping operation, it is possible that the mapping operation itself will create managed objects that should be used to satisfy the connections mappings of representations being mapped. To support such cases, is is desirable to defer the execution of connection operations until the execution of the aggregate mapping operation is complete. The `parentOperation` property provides support for deferring the execution of the enqueued relationship connection operations by establishing a dependency between the connection operations and a parent operation, such as an instance of `RKMapperOperation` such that they will not be executed by the `operationQueue` until the parent operation has finished executing. + */ +@property (nonatomic, weak) NSOperation *parentOperation; + +/** + The operation queue in which instances of `RKRelationshipConnectionOperation` will be enqueued to connect the relationships of mapped objects. + + If `nil`, then current operation queue as returned from `[NSOperationQueue currentQueue]` will be used. + + Please see the documentation for `parentOperation` for a discussion of this property's function. + */ +@property (nonatomic, strong) NSOperationQueue *operationQueue; + +@end diff --git a/Pods/RestKit/Code/CoreData/RKManagedObjectMappingOperationDataSource.m b/Pods/RestKit/Code/CoreData/RKManagedObjectMappingOperationDataSource.m new file mode 100644 index 0000000..cf1ca6d --- /dev/null +++ b/Pods/RestKit/Code/CoreData/RKManagedObjectMappingOperationDataSource.m @@ -0,0 +1,506 @@ +// +// RKManagedObjectMappingOperationDataSource.m +// RestKit +// +// Created by Blake Watters on 7/3/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import +#import "RKManagedObjectMappingOperationDataSource.h" +#import "RKObjectMapping.h" +#import "RKEntityMapping.h" +#import "RKLog.h" +#import "RKManagedObjectStore.h" +#import "RKMappingOperation.h" +#import "RKObjectMappingMatcher.h" +#import "RKManagedObjectCaching.h" +#import "RKRelationshipConnectionOperation.h" +#import "RKMappingErrors.h" +#import "RKValueTransformers.h" +#import "RKRelationshipMapping.h" +#import "RKObjectUtilities.h" +#import "NSManagedObject+RKAdditions.h" + +extern NSString * const RKObjectMappingNestingAttributeKeyName; + +static void *RKManagedObjectMappingOperationDataSourceAssociatedObjectKey = &RKManagedObjectMappingOperationDataSourceAssociatedObjectKey; + +NSArray *RKApplyNestingAttributeValueToMappings(NSString *attributeName, id value, NSArray *propertyMappings); + +static id RKValueForAttributeMappingInRepresentation(RKAttributeMapping *attributeMapping, NSDictionary *representation) +{ + if ([attributeMapping.sourceKeyPath isEqualToString:RKObjectMappingNestingAttributeKeyName]) { + return [[representation allKeys] lastObject]; + } else if (attributeMapping.sourceKeyPath == nil){ + return representation[[NSNull null]]; + } else { + return [representation valueForKeyPath:attributeMapping.sourceKeyPath]; + } +} + +static RKAttributeMapping *RKAttributeMappingForNameInMappings(NSString *name, NSArray *attributeMappings) +{ + for (RKAttributeMapping *attributeMapping in attributeMappings) { + if ([[attributeMapping destinationKeyPath] isEqualToString:name]) return attributeMapping; + } + + return nil; +} + +/** + This function is the workhorse for extracting entity identifier attributes from a dictionary representation. It supports type transformations, compound entity identifier attributes, and dynamic nesting keys within the representation. + */ +static NSDictionary *RKEntityIdentificationAttributesForEntityMappingWithRepresentation(RKEntityMapping *entityMapping, NSDictionary *representation) +{ + NSCParameterAssert(entityMapping); + NSCAssert([representation isKindOfClass:[NSDictionary class]], @"Expected a dictionary representation"); + NSArray *attributeMappings = entityMapping.attributeMappings; + __block NSError *error = nil; + + // If the representation is mapped with a nesting attribute, we must apply the nesting value to the representation before constructing the identification attributes + RKAttributeMapping *nestingAttributeMapping = [entityMapping mappingForSourceKeyPath:RKObjectMappingNestingAttributeKeyName]; + if (nestingAttributeMapping) { + Class attributeClass = [entityMapping classForProperty:nestingAttributeMapping.destinationKeyPath]; + id attributeValue = nil; + id valueTransformer = nestingAttributeMapping.valueTransformer ?: entityMapping.valueTransformer; + [valueTransformer transformValue:[[representation allKeys] lastObject] toValue:&attributeValue ofClass:attributeClass error:&error]; + attributeMappings = RKApplyNestingAttributeValueToMappings(nestingAttributeMapping.destinationKeyPath, attributeValue, attributeMappings); + } + + // Map the identification attributes + NSMutableDictionary *entityIdentifierAttributes = [NSMutableDictionary dictionaryWithCapacity:[entityMapping.identificationAttributes count]]; + [entityMapping.identificationAttributes enumerateObjectsUsingBlock:^(NSAttributeDescription *attribute, NSUInteger idx, BOOL *stop) { + RKAttributeMapping *attributeMapping = RKAttributeMappingForNameInMappings([attribute name], attributeMappings); + Class attributeClass = [entityMapping classForProperty:[attribute name]]; + id sourceValue = RKValueForAttributeMappingInRepresentation(attributeMapping, representation); + id attributeValue = nil; + id valueTransformer = attributeMapping.valueTransformer ?: entityMapping.valueTransformer; + + if (sourceValue) [valueTransformer transformValue:sourceValue toValue:&attributeValue ofClass:attributeClass error:&error]; + entityIdentifierAttributes[[attribute name]] = attributeValue ?: [NSNull null]; + }]; + + return entityIdentifierAttributes; +} + +static id RKMutableCollectionValueWithObjectForKeyPath(id object, NSString *keyPath) +{ + id value = [object valueForKeyPath:keyPath]; + if ([value isKindOfClass:[NSArray class]]) { + return [object mutableArrayValueForKeyPath:keyPath]; + } else if ([value isKindOfClass:[NSSet class]]) { + return [object mutableSetValueForKeyPath:keyPath]; + } else if ([value isKindOfClass:[NSOrderedSet class]]) { + return [object mutableOrderedSetValueForKeyPath:keyPath]; + } else if (value) { + return [NSMutableArray arrayWithObject:value]; + } + + return nil; +} + +// Pre-condition: invoked from the managed object context of the given object +static BOOL RKDeleteInvalidNewManagedObject(NSManagedObject *managedObject) +{ + if ([managedObject isKindOfClass:[NSManagedObject class]] && [managedObject managedObjectContext] && [managedObject isNew]) { + NSError *validationError = nil; + if (! [managedObject validateForInsert:&validationError]) { + RKLogDebug(@"Unsaved NSManagedObject failed `validateForInsert:` - Deleting object from context: %@", validationError); + [managedObject.managedObjectContext deleteObject:managedObject]; + return YES; + } + } + + return NO; +} + +@interface RKManagedObjectDeletionOperation : NSOperation + +- (instancetype)initWithManagedObjectContext:(NSManagedObjectContext *)managedObjectContext; +- (void)addEntityMapping:(RKEntityMapping *)entityMapping; +@end + +@interface RKManagedObjectDeletionOperation () +@property (nonatomic, strong) NSManagedObjectContext *managedObjectContext; +@property (nonatomic, strong) NSMutableSet *entityMappings; +@end + +@implementation RKManagedObjectDeletionOperation + +- (instancetype)initWithManagedObjectContext:(NSManagedObjectContext *)managedObjectContext +{ + self = [self init]; + if (self) { + self.managedObjectContext = managedObjectContext; + self.entityMappings = [NSMutableSet new]; + } + return self; +} + +- (void)addEntityMapping:(RKEntityMapping *)entityMapping +{ + if (! entityMapping.deletionPredicate) return; + [self.entityMappings addObject:entityMapping]; +} + +- (void)main +{ + [self.managedObjectContext performBlockAndWait:^{ + NSMutableSet *objectsToDelete = [NSMutableSet set]; + for (RKEntityMapping *entityMapping in self.entityMappings) { + NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:[entityMapping.entity name]]; + [fetchRequest setPredicate:entityMapping.deletionPredicate]; + NSError *error = nil; + NSArray *fetchedObjects = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error]; + if (fetchedObjects) { + [objectsToDelete addObjectsFromArray:fetchedObjects]; + } + } + + for (NSManagedObject *managedObject in objectsToDelete) { + [self.managedObjectContext deleteObject:managedObject]; + } + }]; + + self.entityMappings = nil; +} + +@end + +// Set Logging Component +#undef RKLogComponent +#define RKLogComponent RKlcl_cRestKitCoreData + +extern NSString * const RKObjectMappingNestingAttributeKeyName; + +@interface RKManagedObjectMappingOperationDataSource () +@property (nonatomic, strong, readwrite) NSManagedObjectContext *managedObjectContext; +@property (nonatomic, strong, readwrite) id managedObjectCache; +@property (nonatomic, strong) NSMutableArray *deletionPredicates; +@end + +@implementation RKManagedObjectMappingOperationDataSource + +- (instancetype)initWithManagedObjectContext:(NSManagedObjectContext *)managedObjectContext cache:(id)managedObjectCache +{ + NSParameterAssert(managedObjectContext); + + self = [self init]; + if (self) { + self.managedObjectContext = managedObjectContext; + self.managedObjectCache = managedObjectCache; + + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(updateCacheWithChangesFromContextWillSaveNotification:) + name:NSManagedObjectContextWillSaveNotification + object:managedObjectContext]; + } + + return self; +} + +- (void)dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + +- (id)mappingOperation:(RKMappingOperation *)mappingOperation targetObjectForMapping:(RKObjectMapping *)mapping inRelationship:(RKRelationshipMapping *)relationship +{ + if (! [mapping isKindOfClass:[RKEntityMapping class]]) { + return [mapping.objectClass new]; + } + + return nil; +} + +- (id)mappingOperation:(RKMappingOperation *)mappingOperation targetObjectForRepresentation:(NSDictionary *)representation withMapping:(RKObjectMapping *)mapping inRelationship:(RKRelationshipMapping *)relationship +{ + NSAssert(representation, @"Mappable data cannot be nil"); + NSAssert(self.managedObjectContext, @"%@ must be initialized with a managed object context.", [self class]); + + if (! [mapping isKindOfClass:[RKEntityMapping class]]) { + return [mapping.objectClass new]; + } + + RKEntityMapping *entityMapping = (RKEntityMapping *)mapping; + NSDictionary *entityIdentifierAttributes = RKEntityIdentificationAttributesForEntityMappingWithRepresentation(entityMapping, representation); + if (! self.managedObjectCache) { + RKLogWarning(@"Performing managed object mapping with a nil managed object cache:\n" + "Unable to update existing object instances by identification attributes. Duplicate objects may be created."); + } + + NSEntityDescription *entity = [entityMapping entity]; + NSManagedObject *managedObject = nil; + + // If we are mapping within a relationship, try to find an existing object without identifying attributes + // NOTE: We avoid doing the mutable(Array|Set|OrderedSet)ValueForKey if there are identification attributes for performance (see issue GH-1232) + if (relationship) { + NSArray *identificationAttributes = [entityMapping.identificationAttributes valueForKey:@"name"]; + id existingObjectsOfRelationship = identificationAttributes ? [mappingOperation.destinationObject valueForKeyPath:relationship.destinationKeyPath] : RKMutableCollectionValueWithObjectForKeyPath(mappingOperation.destinationObject, relationship.destinationKeyPath); + if (existingObjectsOfRelationship && !RKObjectIsCollection(existingObjectsOfRelationship)) existingObjectsOfRelationship = @[ existingObjectsOfRelationship ]; + NSSet *setWithNull = [NSSet setWithObject:[NSNull null]]; + for (NSManagedObject *existingObject in existingObjectsOfRelationship) { + if(existingObject.isDeleted) { + continue; + } + + if (!identificationAttributes) { + managedObject = existingObject; + [existingObjectsOfRelationship removeObject:managedObject]; + break; + } + + NSDictionary *identificationAttributeValues = [existingObject dictionaryWithValuesForKeys:identificationAttributes]; + if ([[NSSet setWithArray:[identificationAttributeValues allValues]] isEqualToSet:setWithNull]) { + managedObject = existingObject; + break; + } + } + } + + // If we have found the entity identification attributes, try to find an existing instance to update + if ([entityIdentifierAttributes count]) { + NSSet *objects = [self.managedObjectCache managedObjectsWithEntity:entity + attributeValues:entityIdentifierAttributes + inManagedObjectContext:self.managedObjectContext]; + if (entityMapping.identificationPredicate) objects = [objects filteredSetUsingPredicate:entityMapping.identificationPredicate]; + if (entityMapping.identificationPredicateBlock) { + NSPredicate *predicate = entityMapping.identificationPredicateBlock(representation, self.managedObjectContext); + if (predicate) objects = [objects filteredSetUsingPredicate:predicate]; + } + if ([objects count] > 0) { + managedObject = [objects anyObject]; + if ([objects count] > 1) RKLogWarning(@"Managed object cache returned %ld objects for the identifier configured for the '%@' entity, expected 1.", (long) [objects count], [entity name]); + } + if (managedObject && [self.managedObjectCache respondsToSelector:@selector(didFetchObject:)]) { + [self.managedObjectCache didFetchObject:managedObject]; + } + } + + if (managedObject == nil) { + NSEntityDescription *localEntity = [NSEntityDescription entityForName:[entity name] inManagedObjectContext:self.managedObjectContext]; + managedObject = [[NSManagedObject alloc] initWithEntity:localEntity insertIntoManagedObjectContext:self.managedObjectContext]; + [managedObject setValuesForKeysWithDictionary:entityIdentifierAttributes]; + if (entityMapping.persistentStore) [self.managedObjectContext assignObject:managedObject toPersistentStore:entityMapping.persistentStore]; + + if ([self.managedObjectCache respondsToSelector:@selector(didCreateObject:)]) { + [self.managedObjectCache didCreateObject:managedObject]; + } + } + + return managedObject; +} + +// Mapping operations should be executed against managed object contexts with the `NSPrivateQueueConcurrencyType` concurrency type +- (BOOL)executingConnectionOperationsWouldDeadlock +{ + return [NSThread isMainThread] && [self.managedObjectContext concurrencyType] == NSMainQueueConcurrencyType && self.operationQueue; +} + +- (void)emitDeadlockWarningIfNecessary +{ + if ([self executingConnectionOperationsWouldDeadlock]) { + RKLogWarning(@"Mapping operation was configured with a managedObjectContext with the `NSMainQueueConcurrencyType` concurrency type" + " and given an operationQueue to perform background work. This configuration will lead to a deadlock with" + " the main queue waiting on the mapping to complete and the operationQueue waiting for access to the MOC." + " You should instead provide a managedObjectContext with the NSPrivateQueueConcurrencyType."); + } +} + +- (BOOL)commitChangesForMappingOperation:(RKMappingOperation *)mappingOperation error:(NSError **)error +{ + if ([mappingOperation.objectMapping isKindOfClass:[RKEntityMapping class]]) { + [self emitDeadlockWarningIfNecessary]; + + RKEntityMapping *entityMapping = (RKEntityMapping *)mappingOperation.objectMapping; + NSArray *connections = [entityMapping connections]; + if ([connections count] > 0 && self.managedObjectCache == nil) { + NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: @"Cannot map an entity mapping that contains connection mappings with a data source whose managed object cache is nil." }; + NSError *localError = [NSError errorWithDomain:RKErrorDomain code:RKMappingErrorNilManagedObjectCache userInfo:userInfo]; + if (error) *error = localError; + return NO; + } + + /** + Attempt to establish the connections and delete the object if its invalid once we are done + + NOTE: We obtain a weak reference to the MOC to avoid a potential crash under iOS 5 if the MOC is deallocated before the operation executes. Under iOS 6, the object returns a nil `managedObjectContext` and the `performBlockAndWait:` message is sent to nil. + */ + NSOperationQueue *operationQueue = self.operationQueue ?: [NSOperationQueue currentQueue]; + __weak NSManagedObjectContext *weakContext = [(NSManagedObject *)mappingOperation.destinationObject managedObjectContext]; + NSBlockOperation *deletionOperation = entityMapping.discardsInvalidObjectsOnInsert ? [NSBlockOperation blockOperationWithBlock:^{ + [weakContext performBlockAndWait:^{ + RKDeleteInvalidNewManagedObject(mappingOperation.destinationObject); + }]; + }] : nil; + + // Add a dependency on the parent operation. If we are being mapped as part of a relationship, then the assignment of the mapped object to a parent may well fulfill the validation requirements. This ensures that the relationship mapping has completed before we evaluate the object for deletion. + if (self.parentOperation) [deletionOperation addDependency:self.parentOperation]; + + RKRelationshipConnectionOperation *connectionOperation = nil; + if ([connections count]) { + connectionOperation = [[RKRelationshipConnectionOperation alloc] initWithManagedObject:mappingOperation.destinationObject connections:connections managedObjectCache:self.managedObjectCache]; + [connectionOperation setConnectionBlock:^(RKRelationshipConnectionOperation *operation, RKConnectionDescription *connection, id connectedValue) { + if (connectedValue) { + if ([mappingOperation.delegate respondsToSelector:@selector(mappingOperation:didConnectRelationship:toValue:usingConnection:)]) { + [mappingOperation.delegate mappingOperation:mappingOperation didConnectRelationship:connection.relationship toValue:connectedValue usingConnection:connection]; + } + } else { + if ([mappingOperation.delegate respondsToSelector:@selector(mappingOperation:didFailToConnectRelationship:usingConnection:)]) { + [mappingOperation.delegate mappingOperation:mappingOperation didFailToConnectRelationship:connection.relationship usingConnection:connection]; + } + } + }]; + + if (self.parentOperation) [connectionOperation addDependency:self.parentOperation]; + [deletionOperation addDependency:connectionOperation]; + [operationQueue addOperation:connectionOperation]; + RKLogTrace(@"Enqueued %@ dependent upon parent operation %@ to operation queue %@", connectionOperation, self.parentOperation, operationQueue); + } + + // Enqueue our deletion operation for execution after all the connections + [operationQueue addOperation:deletionOperation]; + + // Handle tombstone deletion by predicate + if ([(RKEntityMapping *)mappingOperation.objectMapping deletionPredicate]) { + RKManagedObjectDeletionOperation *predicateDeletionOperation = nil; + // Attach a deletion operation for execution after the parent operation completes + predicateDeletionOperation = (RKManagedObjectDeletionOperation *)objc_getAssociatedObject(self.parentOperation, RKManagedObjectMappingOperationDataSourceAssociatedObjectKey); + if (! predicateDeletionOperation) { + predicateDeletionOperation = [[RKManagedObjectDeletionOperation alloc] initWithManagedObjectContext:self.managedObjectContext]; + + // Attach a deletion operation for execution after the parent operation completes + if (self.parentOperation) { + objc_setAssociatedObject(self.parentOperation, RKManagedObjectMappingOperationDataSourceAssociatedObjectKey, predicateDeletionOperation, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + [predicateDeletionOperation addDependency:self.parentOperation]; + } + + // Ensure predicate deletion executes after any connections have been established + if (connectionOperation) [predicateDeletionOperation addDependency:connectionOperation]; + + [operationQueue addOperation:predicateDeletionOperation]; + } + [predicateDeletionOperation addEntityMapping:(RKEntityMapping *)mappingOperation.objectMapping]; + } + } + + return YES; +} + +// NOTE: In theory we should be able to use the userInfo dictionary, but the dictionary was coming in empty (12/18/2012) +- (void)updateCacheWithChangesFromContextWillSaveNotification:(NSNotification *)notification +{ + NSSet *objectsToAdd = [[self.managedObjectContext insertedObjects] setByAddingObjectsFromSet:[self.managedObjectContext updatedObjects]]; + + __block BOOL success; + __block NSError *error = nil; + [self.managedObjectContext performBlockAndWait:^{ + success = [self.managedObjectContext obtainPermanentIDsForObjects:[objectsToAdd allObjects] error:&error]; + }]; + + if (! success) { + RKLogWarning(@"Failed obtaining permanent managed object ID's for %ld objects: the managed object cache was not updated and duplicate objects may be created.", (long) [objectsToAdd count]); + RKLogError(@"Obtaining permanent managed object IDs failed with error: %@", error); + return; + } + + // Update the cache + if ([self.managedObjectCache respondsToSelector:@selector(didFetchObject:)]) { + for (NSManagedObject *managedObject in objectsToAdd) { + [self.managedObjectCache didFetchObject:managedObject]; + } + } + + if ([self.managedObjectCache respondsToSelector:@selector(didDeleteObject:)]) { + for (NSManagedObject *managedObject in [self.managedObjectContext deletedObjects]) { + [self.managedObjectCache didDeleteObject:managedObject]; + } + } +} + +- (BOOL)mappingOperation:(RKMappingOperation *)mappingOperation deleteExistingValueOfRelationshipWithMapping:(RKRelationshipMapping *)relationshipMapping error:(NSError **)error +{ + // Validate the assignment policy + if (relationshipMapping.assignmentPolicy != RKReplaceAssignmentPolicy) { + NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: @"Unable to satisfy deletion request: Relationship mapping was expected to have an assignment policy of `RKReplaceAssignmentPolicy`, but did not." }; + NSError *localError = [NSError errorWithDomain:RKErrorDomain code:RKMappingErrorInvalidAssignmentPolicy userInfo:userInfo]; + if (error) *error = localError; + return NO; + } + + // Delete any managed objects at the destination key path from the context + id existingValue = [mappingOperation.destinationObject valueForKeyPath:relationshipMapping.destinationKeyPath]; + if ([existingValue isKindOfClass:[NSManagedObject class]]) { + [self.managedObjectContext deleteObject:existingValue]; + } else { + if (RKObjectIsCollection(existingValue)) { + for (NSManagedObject *managedObject in existingValue) { + if (! [managedObject isKindOfClass:[NSManagedObject class]]) continue; + [self.managedObjectContext deleteObject:managedObject]; + } + } + } + + return YES; +} + +- (BOOL)mappingOperationShouldSetUnchangedValues:(RKMappingOperation *)mappingOperation +{ + // Only new objects should have a temporary ID + if ([mappingOperation.destinationObject isKindOfClass:[NSManagedObject class]]) { + return [[(NSManagedObject *)mappingOperation.destinationObject objectID] isTemporaryID]; + } + + return [mappingOperation isNewDestinationObject]; +} + +- (BOOL)mappingOperationShouldSkipPropertyMapping:(RKMappingOperation *)mappingOperation +{ + // Use concrete mapping or original mapping if not available + RKMapping *checkedMapping = mappingOperation.objectMapping ?: mappingOperation.mapping; + + if (! [checkedMapping isKindOfClass:[RKEntityMapping class]]) return NO; + RKEntityMapping *entityMapping = (RKEntityMapping *)checkedMapping; + NSString *modificationKey = [entityMapping.modificationAttribute name]; + if (! modificationKey) return NO; + id currentValue = [mappingOperation.destinationObject valueForKey:modificationKey]; + if (! currentValue) return NO; + if (! [currentValue respondsToSelector:@selector(compare:)]) return NO; + + RKPropertyMapping *propertyMappingForModificationKey = [(RKEntityMapping *)checkedMapping mappingForDestinationKeyPath:modificationKey]; + id rawValue = [[mappingOperation sourceObject] valueForKeyPath:propertyMappingForModificationKey.sourceKeyPath]; + if (! rawValue) return NO; + Class attributeClass = [entityMapping classForProperty:propertyMappingForModificationKey.destinationKeyPath]; + + id transformedValue = nil; + NSError *error = nil; + id valueTransformer = propertyMappingForModificationKey.valueTransformer ?: entityMapping.valueTransformer; + [valueTransformer transformValue:rawValue toValue:&transformedValue ofClass:attributeClass error:&error]; + if (! transformedValue) return NO; + + if ([currentValue isKindOfClass:[NSString class]]) { + return [currentValue isEqualToString:transformedValue]; + } else { + return [currentValue compare:transformedValue] != NSOrderedAscending; + } +} + +- (BOOL)mappingOperationShouldCollectMappingInfo:(RKMappingOperation *)mappingOperation +{ + return YES; +} + +@end diff --git a/Pods/RestKit/Code/CoreData/RKManagedObjectStore.h b/Pods/RestKit/Code/CoreData/RKManagedObjectStore.h new file mode 100644 index 0000000..d11ecf3 --- /dev/null +++ b/Pods/RestKit/Code/CoreData/RKManagedObjectStore.h @@ -0,0 +1,307 @@ +// +// RKManagedObjectStore.h +// RestKit +// +// Created by Blake Watters on 9/22/09. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import +#import "RKEntityMapping.h" +#import "RKManagedObjectCaching.h" + +@class RKManagedObjectStore; + +/** + The `RKManagedObjectStore` class encapsulates a Core Data stack including a managed object model, a persistent store coordinator, and a set of managed object contexts. The managed object store simplifies the task of properly setting up a Core Data stack and provides some additional functionality, such as the use of a seed database to initialize a SQLite backed persistent store and a simple code path for resetting the store by destroying and recreating the persistent stores. + + ## Initialization + + The managed object store is designed to easily initialize a Core Data stack in a recommended configuration. A store object must always be initialized with a managed object model, but this managed object model can be directly provided, inferred from an already configured persistent store coordinator, or read from the currently available bundles within the application. Note that several features provided by the framework rely on the store being initialized with a mutable managed object model. Please refer to the documentation in the `initWithManagedObjectModel:` for details. + + ## Managed Object Contexts + + The managed object store provides the application developer with a pair of managed object contexts with which to work with Core Data. The store configures a primary managed object context with the NSPrivateQueueConcurrencyType that is associated with the persistent store coordinator for handling Core Data persistence. A second context is also created with the NSMainQueueConcurrencyType that is a child of the primary managed object context for doing work on the main queue. Additional child contexts can be created directly or via a convenience method interface provided by the store (see newChildManagedObjectContextWithConcurrencyType:tracksChanges:). + + The managed object context hierarchy is designed to isolate the main thread from disk I/O and avoid deadlocks. Because the primary context manages its own private queue, saving the main queue context will not result in the objects being saved to the persistent store. The primary context must be saved as well for objects to be persisted to disk. + + It is also worth noting that because of the parent/child context hierarchy, objects created on the main thread will not obtain permanent managed object ID's even after the primary context has been saved. If you need to refer to the permanent representations of objects created on the main thread after a save, you may ask the main queue context to obtain permanent managed objects for your objects via `obtainPermanentIDsForObjects:error:`. Be warned that when obtaining permanent managed object ID's, you must include all newly created objects that are reachable from the object you are concerned with in the set of objects provided to `obtainPermanentIDsForObjects:error:`. This means any newly created object in a one-to-one or one-to-many relationship must be provided or you will face a crash from the managed object context. This is due to a bug in Core Data still present in iOS5, but fixed in iOS6 (see Open Radar http://openradar.appspot.com/11478919). + */ +@interface RKManagedObjectStore : NSObject + +///----------------------------------------- +/// @name Accessing the Default Object Store +///----------------------------------------- + +/** + Returns the default managed object store for the application. + + @return The default managed object store. + */ ++ (instancetype)defaultStore; + +/** + Sets the default managed object store for the application. + + @param managedObjectStore The new default managed object store. + */ ++ (void)setDefaultStore:(RKManagedObjectStore *)managedObjectStore; + +///----------------------------------- +/// @name Initializing an Object Store +///----------------------------------- + +/** + Initializes the receiver with a given managed object model. This is the designated initializer for `RKManagedObjectStore`. + + @param managedObjectModel The managed object model with which to initialize the receiver. + @return The receiver, initialized with the given managed object model. + @bug Several features require that the managed object model used to initialize the store be mutable so that entities may be changed before the persistent store coordinator is created. Since iOS 5, managed object models initialized via initWithContentsOfURL: return an immutable model. The application developer must send the returned managed object model a mutable copy message to ensure that it is mutable before initializing the managed object store. The recommended approach for initializing a managed object store is as follows: + + NSURL *modelURL = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"MyApplication" ofType:@"momd"]]; + // NOTE: Due to an iOS 5 bug, the managed object model returned is immutable. + NSManagedObjectModel *managedObjectModel = [[[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL] mutableCopy]; + RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:managedObjectModel]; + + */ +- (instancetype)initWithManagedObjectModel:(NSManagedObjectModel *)managedObjectModel NS_DESIGNATED_INITIALIZER; + +/** + Initializes the receiver with an existing persistent store coordinator. + + The managed object model from the persistent store coordinator will be used to initialize the receiver and the given persistent store coordinator will be configured as the persistent store coordinator for the managed object store. + + This initialization method provides for easy integration with an existing Core Data stack. + + @param persistentStoreCoordinator The persistent store coordinator with which to initialize the receiver. + @return The receiver, initialized with the managed object model of the given persistent store coordinator and the persistent store coordinator. + */ +- (instancetype)initWithPersistentStoreCoordinator:(NSPersistentStoreCoordinator *)persistentStoreCoordinator; + +/** + Initializes the receiver with a managed object model obtained by merging the models from all of the application's non-framework bundles. + + @see `[NSBundle allBundles]` + @see `[NSManagedObjectModel mergedModelFromBundles:]` + + @warning Obtaining a managed object model by merging all bundles may result in an application error if versioned object models are in use. + */ +- (instancetype)init; + +///----------------------------------------------------------------------------- +/// @name Configuring Persistent Stores +///----------------------------------------------------------------------------- + +/** + Creates a persistent store coordinator with the receiver's managed object model. After invocation, the persistentStoreCoordinator property will no longer be nil. + + @warning Creating the persistent store coordinator will render the managed object model immutable. Attempts to use functionality that requires a mutable managed object model after the persistent store coordinator has been created will raise an application error. + */ +- (void)createPersistentStoreCoordinator; + +/** + Adds a new in memory persistent store to the persistent store coordinator of the receiver. + + This method will invoke createPersistentStore if a persistent store coordinator has not yet been created. + + @param error On input, a pointer to an error object. If an error occurs, this pointer is set to an actual error object containing the error information. You may specify nil for this parameter if you do not want the error information. + @returns The new persistent store, or nil in the event of an error. + */ +- (NSPersistentStore *)addInMemoryPersistentStore:(NSError **)error; + +/** + Adds a new SQLite persistent store, optionally initialized with a seed database, to the persistent store coordinator of the receiver. + + @param storePath The path at which to save the persistent store on disk. + @param seedPath An optional path to a seed database to copy to the given storePath in the event that a store does not yet exist. + @param nilOrConfigurationName An optional name of a Core Data configuration in the managed object model. + @param nilOrOptions An optional dictionary of options with which to configure the persistent store. If `nil`, a dictionary of options enabling `NSMigratePersistentStoresAutomaticallyOption` and `NSInferMappingModelAutomaticallyOption` will be used. + @param error On input, a pointer to an error object. If an error occurs, this pointer is set to an actual error object containing the error information. You may specify nil for this parameter if you do not want the error information. + + @bug Note that when built for iOS, this method will set a resource value on the SQLite file backing the persistent store for the `NSURLIsExcludedFromBackupKey` key set to `YES` to exclude the SQLite file from being backed up by iCloud to conform with the ["iOS Data Storage Guidelines"](https://developer.apple.com/icloud/documentation/data-storage/) + @warning If the seed database at the given path was created with an incompatible managed object model an application error may be raised. + */ +- (NSPersistentStore *)addSQLitePersistentStoreAtPath:(NSString *)storePath + fromSeedDatabaseAtPath:(NSString *)seedPath + withConfiguration:(NSString *)nilOrConfigurationName + options:(NSDictionary *)nilOrOptions + error:(NSError **)error; + +/** + Resets the persistent stores in the receiver's persistent store coordinator and recreates them. If a store being reset is backed by a file on disk (such as a SQLite file), the file will be removed prior to recreating the store. If the store was originally created using a seed database, the seed will be recopied to reset the store to its seeded state. If the managed object model uses External Storage for any of its entities, then the external storage directory will be recursively deleted when the store is reset. + + @param error On input, a pointer to an error object. If an error occurs, this pointer is set to an actual error object containing the error information. You may specify nil for this parameter if you do not want the error information. + @return A Boolean value indicating if the reset was successful. + + @bug This method will implictly result in the managed object contexts associated with the receiver to be discarded and recreated. Any managed objects or additional child contexts associated with the store will need to be discarded or else exceptions may be raised (i.e. `NSObjectInaccessibleException`). + + Also note that care must be taken to cancel/suspend all mapping operations, reset all managed object contexts, and disconnect all `NSFetchedResultController` objects that are associated with managed object contexts using the persistent stores of the receiver before attempting a reset. Failure to completely disconnect usage before calling this method is likely to result in a deadlock. + + As an alternative to resetting the persistent store, you may wish to consider simply deleting all managed objects out of the managed object context. If your data set is not very large, this can be a performant operation and is significantly easier to implement correctly. An example implementation for truncating all managed objects from the store is provided below: + + NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{ + NSManagedObjectContext *managedObjectContext = [RKManagedObjectStore defaultStore].persistentStoreManagedObjectContext; + [managedObjectContext performBlockAndWait:^{ + NSError *error = nil; + for (NSEntityDescription *entity in [RKManagedObjectStore defaultStore].managedObjectModel) { + NSFetchRequest *fetchRequest = [NSFetchRequest new]; + [fetchRequest setEntity:entity]; + [fetchRequest setIncludesSubentities:NO]; + NSArray *objects = [managedObjectContext executeFetchRequest:fetchRequest error:&error]; + if (! objects) RKLogWarning(@"Failed execution of fetch request %@: %@", fetchRequest, error); + for (NSManagedObject *managedObject in objects) { + [managedObjectContext deleteObject:managedObject]; + } + } + + BOOL success = [managedObjectContext save:&error]; + if (!success) RKLogWarning(@"Failed saving managed object context: %@", error); + }]; + }]; + [operation setCompletionBlock:^{ + // Do stuff once the truncation is complete + }]; + [operation start]; + */ +- (BOOL)resetPersistentStores:(NSError **)error; + +///----------------------------------------- +/// @name Retrieving Details about the Store +///----------------------------------------- + +/** + Returns the managed object model of the receiver. + + @return The managed object model of the receiver. + */ +@property (nonatomic, strong, readonly) NSManagedObjectModel *managedObjectModel; + +/** + Returns the persistent store coordinator of the receiver. + + @return The persistent store coordinator of the receiver. + */ +@property (nonatomic, strong, readonly) NSPersistentStoreCoordinator *persistentStoreCoordinator; + +/** + The managed object cache associated with the receiver. + + The managed object cache is used to accelerate intensive Core Data operations by caching managed objects by one or more attributes. + + **Default**: An instance of `RKFetchRequestManagedObjectCache`. + + @see `RKManagedObjectCaching` + @warning A nil managed object cache will result in a store that is unable to uniquely identify existing objects by identification attributes and may result in the creation of duplicate objects within the store. + */ +@property (nonatomic, strong) id managedObjectCache; + +///------------------------------------------- +/// @name Working with Managed Object Contexts +///------------------------------------------- + +/** + Creates the persistent store and main queue managed object contexts for the receiver. + + @see `persistentStoreManagedObjectContext` + @see `mainQueueManagedObjectContext` + @raises NSInternalInconsistencyException Raised if the managed object contexts have already been created. + */ +- (void)createManagedObjectContexts; + +/** + Returns the managed object context of the receiver that is associated with the persistent store coordinator and is responsible for managing persistence. + + The persistent store context is created with the `NSPrivateQueueConcurrencyType` and as such must be interacted with using `[NSManagedObjectContext performBlock:]` or `[NSManagedObjectContext performBlockAndWait:]`. This context typically serves as the parent context for scratch contexts or main queue contexts for interacting with the user interface. Created by the invocation of `createManagedObjectContexts`. + + @see `createManagedObjectContexts` + */ +@property (nonatomic, strong, readonly) NSManagedObjectContext *persistentStoreManagedObjectContext; + +/** + The main queue managed object context of the receiver. + + The main queue context is available for usage on the main queue to drive user interface needs. The context is created with the NSMainQueueConcurrencyType and as such may be messaged directly from the main thread. The context is a child context of the persistentStoreManagedObjectContext and can persist changes up to the parent via a save. + */ +@property (nonatomic, strong, readonly) NSManagedObjectContext *mainQueueManagedObjectContext; + +/** + Creates a new child managed object context of the persistent store managed object context with a given concurrency type, optionally tracking changes saved to the parent context and merging them on save. + + @param concurrencyType The desired concurrency type for the new context. + @param tracksChanges When `YES`, the new context will observe the `persistentStoreManagedObjectContext` for save events and merge in any changes via `[NSManagedObjectContext mergeChangesFromContextDidSaveNotification:]`. + @return A newly created managed object context with the given concurrency type whose parent is the `persistentStoreManagedObjectContext`. + */ +- (NSManagedObjectContext *)newChildManagedObjectContextWithConcurrencyType:(NSManagedObjectContextConcurrencyType)concurrencyType tracksChanges:(BOOL)tracksChanges; +- (NSManagedObjectContext *)newChildManagedObjectContextWithConcurrencyType:(NSManagedObjectContextConcurrencyType)concurrencyType DEPRECATED_ATTRIBUTE; // invokes above with `tracksChanges:NO` + +///---------------------------- +/// @name Performing Migrations +///---------------------------- + +/** + Performs a migration on a persistent store at a given URL to the model at the specified URL. + + This method provides support for migrating persistent stores in which the source and destination models have been mutated after being loaded from the model archive on disk, such as when the RestKit managed object searching support is used. In a situation where the persistent store has been created with a dynamically modified managed object model. Core Data is unable to infer the mapping model because the metadata of the persistent store does not agree with that of the managed object model due to the dynamic modifications. In order to perform a migration, one must load the appropriate source model, apply the dynamic changes appropriate for that model, then infer a mapping model from the modified model. This method assists in this process by accepting a source store and a destination model as arguments and searching through all models in the .momd package and yielding each model to the given configuration block for processing. After the block is invoked, the metadata of the store is checked for compatibility with the modified managed object model to identify the source store. Once the source store is found, a mapping model is inferred and the migration proceeds. The migration is done against a copy of the given persistent store and if successful, the migrated store is moved to replace the original store. + + To understand how this is used, consider the following example: Given a managed object model containing two entities 'Article' and 'Tag', the user wishes to configure managed object search indexing on the models and wishes to be able to migrate existing persistent stores across versions. The migration configuration would look something like this: + + NSURL *storeURL = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"MyStore.sqlite"]; + NSURL *modelURL = [[RKTestFixture fixtureBundle] URLForResource:@"VersionedModel" withExtension:@"momd"]; + BOOL success = [RKManagedObjectStore migratePersistentStoreOfType:NSSQLiteStoreType atURL:storeURL toModelAtURL:modelURL error:&error configuringModelsWithBlock:^(NSManagedObjectModel *model, NSURL *sourceURL) { + // Examine each model and configure search indexing appropriately based on the versionIdentifiers configured in the model + if ([[model versionIdentifiers] isEqualToSet:[NSSet setWithObject:@"1.0"]]) { + NSEntityDescription *articleEntity = [[model entitiesByName] objectForKey:@"Article"]; + NSEntityDescription *tagEntity = [[model entitiesByName] objectForKey:@"Tag"]; + [RKSearchIndexer addSearchIndexingToEntity:articleEntity onAttributes:@[ @"title" ]]; + [RKSearchIndexer addSearchIndexingToEntity:tagEntity onAttributes:@[ @"name" ]]; + } else if ([[model versionIdentifiers] isEqualToSet:[NSSet setWithObject:@"2.0"]]) { + NSEntityDescription *articleEntity = [[model entitiesByName] objectForKey:@"Article"]; + NSEntityDescription *tagEntity = [[model entitiesByName] objectForKey:@"Tag"]; + [RKSearchIndexer addSearchIndexingToEntity:articleEntity onAttributes:@[ @"title", @"body" ]]; + [RKSearchIndexer addSearchIndexingToEntity:tagEntity onAttributes:@[ @"name" ]]; + } else if ([[model versionIdentifiers] containsObject:@"3.0"] || [[model versionIdentifiers] containsObject:@"4.0"]) { + // We index the same attributes on v3 and v4 + NSEntityDescription *articleEntity = [[model entitiesByName] objectForKey:@"Article"]; + NSEntityDescription *tagEntity = [[model entitiesByName] objectForKey:@"Tag"]; + [RKSearchIndexer addSearchIndexingToEntity:articleEntity onAttributes:@[ @"title", @"body", @"authorName" ]]; + [RKSearchIndexer addSearchIndexingToEntity:tagEntity onAttributes:@[ @"name" ]]; + } + }]; + + @param storeType The type of store that given URL. May be `nil`. + @param storeURL A URL to the store that is to be migrated. + @param destinationModelURL A URL to the managed object model that the persistent store is to be updated to. This URL may target a specific model version with a .momd package or point to the .momd package itself, in which case the migration is performed to the current version of the model as configured on the .xcdatamodeld file used to the build the .momd package. + @param error A pointer to an error object that is set in the event that the migration is unsuccessful. + @param block A block object used to configure + + @warning This method is only usable with a versioned Managed Object Model stored as a .momd package containing .mom managed object model archives. + */ ++ (BOOL)migratePersistentStoreOfType:(NSString *)storeType + atURL:(NSURL *)storeURL + toModelAtURL:(NSURL *)destinationModelURL + error:(NSError **)error + configuringModelsWithBlock:(void (^)(NSManagedObjectModel *model, NSURL *sourceURL))block; + +@end + +/** + Option containing the path to the seed database a SQLite store was initialized with + **/ +extern NSString *const RKSQLitePersistentStoreSeedDatabasePathOption; + +/** + Posted when a managed object context has reset its persistent stores. + */ +extern NSString *const RKManagedObjectStoreDidResetPersistentStoresNotification; diff --git a/Pods/RestKit/Code/CoreData/RKManagedObjectStore.m b/Pods/RestKit/Code/CoreData/RKManagedObjectStore.m new file mode 100644 index 0000000..ef9f96e --- /dev/null +++ b/Pods/RestKit/Code/CoreData/RKManagedObjectStore.m @@ -0,0 +1,562 @@ +// +// RKManagedObjectStore.m +// RestKit +// +// Created by Blake Watters on 9/22/09. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import +#import "RKManagedObjectStore.h" +#import "RKLog.h" +#import "RKPropertyInspector.h" +#import "RKPropertyInspector+CoreData.h" +#import "RKPathUtilities.h" +#import "RKInMemoryManagedObjectCache.h" +#import "RKFetchRequestManagedObjectCache.h" +#import "NSManagedObjectContext+RKAdditions.h" + +// Set Logging Component +#undef RKLogComponent +#define RKLogComponent RKlcl_cRestKitCoreData + +extern NSString *const RKErrorDomain; + +NSString *const RKSQLitePersistentStoreSeedDatabasePathOption = @"RKSQLitePersistentStoreSeedDatabasePathOption"; +NSString *const RKManagedObjectStoreDidFailSaveNotification = @"RKManagedObjectStoreDidFailSaveNotification"; +NSString *const RKManagedObjectStoreDidResetPersistentStoresNotification = @"RKManagedObjectStoreDidResetPersistentStoresNotification"; + +static RKManagedObjectStore *defaultStore = nil; + +static BOOL RKIsManagedObjectContextDescendentOfContext(NSManagedObjectContext *childContext, NSManagedObjectContext *potentialAncestor) +{ + NSManagedObjectContext *context = [childContext parentContext]; + while (context) { + if ([context isEqual:potentialAncestor]) return YES; + context = [context parentContext]; + } + return NO; +} + +static NSSet *RKSetOfManagedObjectIDsFromManagedObjectContextDidSaveNotification(NSNotification *notification) +{ + NSUInteger count = [[[notification.userInfo allValues] valueForKeyPath:@"@sum.@count"] unsignedIntegerValue]; + NSMutableSet *objectIDs = [NSMutableSet setWithCapacity:count]; + for (NSSet *objects in [notification.userInfo allValues]) { + [objectIDs unionSet:[objects valueForKey:@"objectID"]]; + } + return objectIDs; +} + +@interface RKManagedObjectContextChangeMergingObserver : NSObject +@property (nonatomic, weak) NSManagedObjectContext *observedContext; +@property (nonatomic, weak) NSManagedObjectContext *mergeContext; +@property (nonatomic, strong) NSSet *objectIDsFromChildDidSaveNotification; + +- (instancetype)initWithObservedContext:(NSManagedObjectContext *)observedContext mergeContext:(NSManagedObjectContext *)mergeContext NS_DESIGNATED_INITIALIZER; +@end + +@implementation RKManagedObjectContextChangeMergingObserver + +- (instancetype)initWithObservedContext:(NSManagedObjectContext *)observedContext mergeContext:(NSManagedObjectContext *)mergeContext +{ + if (! observedContext) [NSException raise:NSInvalidArgumentException format:@"observedContext cannot be `nil`."]; + if (! mergeContext) [NSException raise:NSInvalidArgumentException format:@"mergeContext cannot be `nil`."]; + self = [super init]; + if (self) { + self.observedContext = observedContext; + self.mergeContext = mergeContext; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleManagedObjectContextDidSaveNotification:) name:NSManagedObjectContextDidSaveNotification object:observedContext]; + + if (RKIsManagedObjectContextDescendentOfContext(mergeContext, observedContext)) { + RKLogDebug(@"Detected observation of ancestor context by child: enabling child context save detection"); + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleManagedObjectContextWillSaveNotification:) name:NSManagedObjectContextDidSaveNotification object:mergeContext]; + } + } + return self; +} + +- (void)dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + +- (void)handleManagedObjectContextWillSaveNotification:(NSNotification *)notification +{ + self.objectIDsFromChildDidSaveNotification = RKSetOfManagedObjectIDsFromManagedObjectContextDidSaveNotification(notification); +} + +- (void)handleManagedObjectContextDidSaveNotification:(NSNotification *)notification +{ + NSAssert([notification object] == self.observedContext, @"Received Managed Object Context Did Save Notification for Unexpected Context: %@", [notification object]); + if (! [self.objectIDsFromChildDidSaveNotification isEqual:RKSetOfManagedObjectIDsFromManagedObjectContextDidSaveNotification(notification)]) { + [self.mergeContext performBlock:^{ + + /* + Fault updated objects before merging changes into mainQueueManagedObjectContext. + + This enables NSFetchedResultsController to update and re-sort its fetch results and to call its delegate methods + in response Managed Object updates merged from another context. + See: + http://stackoverflow.com/a/3927811/489376 + http://stackoverflow.com/a/16296365/489376 + for issue details. + */ + for (NSManagedObject *object in [[notification userInfo] objectForKey:NSUpdatedObjectsKey]) { + NSManagedObjectID *objectID = [object objectID]; + if (objectID && ![objectID isTemporaryID]) { + NSError *error = nil; + NSManagedObject * updatedObject = [self.mergeContext existingObjectWithID:objectID error:&error]; + if (error) { + RKLogDebug(@"Failed to get existing object for objectID (%@). Failed with error: %@", objectID, error); + } + else { + [updatedObject willAccessValueForKey:nil]; + } + } + } + + [self.mergeContext mergeChangesFromContextDidSaveNotification:notification]; + }]; + } else { + RKLogDebug(@"Skipping merge of `NSManagedObjectContextDidSaveNotification`: the save event originated from the mergeContext and thus no save is necessary."); + } + self.objectIDsFromChildDidSaveNotification = nil; +} + +@end + +static char RKManagedObjectContextChangeMergingObserverAssociationKey; + +@interface RKManagedObjectStore () +@property (nonatomic, strong, readwrite) NSManagedObjectModel *managedObjectModel; +@property (nonatomic, strong, readwrite) NSPersistentStoreCoordinator *persistentStoreCoordinator; +@property (nonatomic, strong, readwrite) NSManagedObjectContext *persistentStoreManagedObjectContext; +@property (nonatomic, strong, readwrite) NSManagedObjectContext *mainQueueManagedObjectContext; +@end + +@implementation RKManagedObjectStore + ++ (instancetype)defaultStore +{ + return defaultStore; +} + ++ (void)setDefaultStore:(RKManagedObjectStore *)managedObjectStore +{ + if (defaultStore) { + @synchronized(defaultStore) { + defaultStore = managedObjectStore; + } + } else { + defaultStore = managedObjectStore; + } +} + +- (instancetype)initWithManagedObjectModel:(NSManagedObjectModel *)managedObjectModel +{ + self = [super init]; + if (self) { + self.managedObjectModel = managedObjectModel; + self.managedObjectCache = [RKFetchRequestManagedObjectCache new]; + + // Hydrate the defaultStore + if (! defaultStore) { + [RKManagedObjectStore setDefaultStore:self]; + } + } + + return self; +} + +- (instancetype)initWithPersistentStoreCoordinator:(NSPersistentStoreCoordinator *)persistentStoreCoordinator +{ + self = [self initWithManagedObjectModel:persistentStoreCoordinator.managedObjectModel]; + if (self) { + self.persistentStoreCoordinator = persistentStoreCoordinator; + } + + return self; +} + +- (instancetype)init +{ + NSManagedObjectModel *managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:[NSBundle allBundles]]; + return [self initWithManagedObjectModel:managedObjectModel]; +} + +- (void)dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + +- (void)createPersistentStoreCoordinator +{ + self.persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:self.managedObjectModel]; +} + +- (NSPersistentStore *)addInMemoryPersistentStore:(NSError **)error +{ + if (! self.persistentStoreCoordinator) [self createPersistentStoreCoordinator]; + + return [self.persistentStoreCoordinator addPersistentStoreWithType:NSInMemoryStoreType configuration:nil URL:nil options:nil error:error]; +} + +- (NSPersistentStore *)addSQLitePersistentStoreAtPath:(NSString *)storePath + fromSeedDatabaseAtPath:(NSString *)seedPath + withConfiguration:(NSString *)nilOrConfigurationName + options:(NSDictionary *)nilOrOptions + error:(NSError **)error +{ + if (! self.persistentStoreCoordinator) [self createPersistentStoreCoordinator]; + + NSURL *storeURL = [NSURL fileURLWithPath:storePath]; + + if (seedPath) { + BOOL success = [self copySeedDatabaseIfNecessaryFromPath:seedPath toPath:storePath error:error]; + if (! success) return nil; + } + + NSDictionary *options = nil; + if (nilOrOptions) { + NSMutableDictionary *mutableOptions = [nilOrOptions mutableCopy]; + mutableOptions[RKSQLitePersistentStoreSeedDatabasePathOption] = (seedPath ?: [NSNull null]); + options = mutableOptions; + } else { + options = @{ RKSQLitePersistentStoreSeedDatabasePathOption: (seedPath ?: [NSNull null]), + NSMigratePersistentStoresAutomaticallyOption: @(YES), + NSInferMappingModelAutomaticallyOption: @(YES) }; + } + + /** + There seems to be trouble with combining configurations and migration. So do this in two steps: first, attach the store with NO configuration, but WITH migration options; then remove it and reattach WITH configuration, but NOT migration options. + + http://blog.atwam.com/blog/2012/05/11/multiple-persistent-stores-and-seed-data-with-core-data/ + http://stackoverflow.com/questions/1774359/core-data-migration-error-message-model-does-not-contain-configuration-xyz + */ + NSPersistentStore *persistentStore = [self.persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:error]; + if (! persistentStore) return nil; + if (! [self.persistentStoreCoordinator removePersistentStore:persistentStore error:error]) return nil; + + NSDictionary *seedOptions = nil; + if (nilOrOptions) { + NSMutableDictionary *mutableOptions = [nilOrOptions mutableCopy]; + mutableOptions[RKSQLitePersistentStoreSeedDatabasePathOption] = (seedPath ?: [NSNull null]); + seedOptions = mutableOptions; + } else { + seedOptions = @{ RKSQLitePersistentStoreSeedDatabasePathOption: (seedPath ?: [NSNull null]) }; + } + persistentStore = [self.persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nilOrConfigurationName URL:storeURL options:seedOptions error:error]; + if (! persistentStore) return nil; + + // Exclude the SQLite database from iCloud Backups to conform to the iCloud Data Storage Guidelines + RKSetExcludeFromBackupAttributeForItemAtPath(storePath); + + return persistentStore; +} + +- (BOOL)copySeedDatabaseIfNecessaryFromPath:(NSString *)seedPath toPath:(NSString *)storePath error:(NSError **)error +{ + if (NO == [[NSFileManager defaultManager] fileExistsAtPath:storePath]) { + NSError *localError; + if (![[NSFileManager defaultManager] copyItemAtPath:seedPath toPath:storePath error:&localError]) { + RKLogError(@"Failed to copy seed database from path '%@' to path '%@': %@", seedPath, storePath, [localError localizedDescription]); + if (error) *error = localError; + + return NO; + } + if ([[NSFileManager defaultManager] fileExistsAtPath:[seedPath stringByAppendingString:@"-shm"]]) { + if (![[NSFileManager defaultManager] copyItemAtPath:[seedPath stringByAppendingString:@"-shm"] toPath:[storePath stringByAppendingString:@"-shm"] error:&localError]) { + RKLogError(@"Failed to copy seed database (SHM) from path '%@' to path '%@': %@", seedPath, storePath, [localError localizedDescription]); + if (error) *error = localError; + + return NO; + } + } + if ([[NSFileManager defaultManager] fileExistsAtPath:[seedPath stringByAppendingString:@"-wal"]]) { + if (![[NSFileManager defaultManager] copyItemAtPath:[seedPath stringByAppendingString:@"-wal"] toPath:[storePath stringByAppendingString:@"-wal"] error:&localError]) { + RKLogError(@"Failed to copy seed database (WAL) from path '%@' to path '%@': %@", seedPath, storePath, [localError localizedDescription]); + if (error) *error = localError; + + return NO; + } + } + } + + return YES; +} + +- (NSManagedObjectContext *)newChildManagedObjectContextWithConcurrencyType:(NSManagedObjectContextConcurrencyType)concurrencyType tracksChanges:(BOOL)tracksChanges +{ + NSManagedObjectContext *managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:concurrencyType]; + [managedObjectContext performBlockAndWait:^{ + managedObjectContext.parentContext = self.persistentStoreManagedObjectContext; + managedObjectContext.mergePolicy = NSMergeByPropertyStoreTrumpMergePolicy; + }]; + + if (tracksChanges) { + RKManagedObjectContextChangeMergingObserver *observer = [[RKManagedObjectContextChangeMergingObserver alloc] initWithObservedContext:self.persistentStoreManagedObjectContext mergeContext:managedObjectContext]; + objc_setAssociatedObject(managedObjectContext, + &RKManagedObjectContextChangeMergingObserverAssociationKey, + observer, + OBJC_ASSOCIATION_RETAIN); + } + + return managedObjectContext; +} + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-implementations" +- (NSManagedObjectContext *)newChildManagedObjectContextWithConcurrencyType:(NSManagedObjectContextConcurrencyType)concurrencyType +{ + return [self newChildManagedObjectContextWithConcurrencyType:concurrencyType tracksChanges:NO]; +} +#pragma clang diagnostic pop + +- (void)createManagedObjectContexts +{ + NSAssert(!self.persistentStoreManagedObjectContext, @"Unable to create managed object contexts: A primary managed object context already exists."); + NSAssert(!self.mainQueueManagedObjectContext, @"Unable to create managed object contexts: A main queue managed object context already exists."); + NSAssert([[self.persistentStoreCoordinator persistentStores] count], @"Cannot create managed object contexts: The persistent store coordinator does not have any persistent stores. This likely means that you forgot to add a persistent store or your attempt to do so failed with an error."); + + // Our primary MOC is a private queue concurrency type + self.persistentStoreManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]; + self.persistentStoreManagedObjectContext.persistentStoreCoordinator = self.persistentStoreCoordinator; + self.persistentStoreManagedObjectContext.mergePolicy = NSMergeByPropertyStoreTrumpMergePolicy; + + // Create an MOC for use on the main queue + self.mainQueueManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType]; + self.mainQueueManagedObjectContext.parentContext = self.persistentStoreManagedObjectContext; + self.mainQueueManagedObjectContext.mergePolicy = NSMergeByPropertyStoreTrumpMergePolicy; + + // Merge changes from a primary MOC back into the main queue when complete + RKManagedObjectContextChangeMergingObserver *observer = [[RKManagedObjectContextChangeMergingObserver alloc] initWithObservedContext:self.persistentStoreManagedObjectContext mergeContext:self.mainQueueManagedObjectContext]; + objc_setAssociatedObject(self.mainQueueManagedObjectContext, + &RKManagedObjectContextChangeMergingObserverAssociationKey, + observer, + OBJC_ASSOCIATION_RETAIN); +} + +- (void)recreateManagedObjectContexts +{ + [[NSNotificationCenter defaultCenter] removeObserver:self name:NSManagedObjectContextDidSaveNotification object:self.persistentStoreManagedObjectContext]; + + self.persistentStoreManagedObjectContext = nil; + self.mainQueueManagedObjectContext = nil; + [self createManagedObjectContexts]; +} + +- (BOOL)resetPersistentStores:(NSError **)error +{ + [self.mainQueueManagedObjectContext performBlockAndWait:^{ + [self.mainQueueManagedObjectContext reset]; + }]; + [self.persistentStoreManagedObjectContext performBlockAndWait:^{ + [self.persistentStoreManagedObjectContext reset]; + }]; + + NSError *localError; + for (NSPersistentStore *persistentStore in self.persistentStoreCoordinator.persistentStores) { + NSURL *URL = [self.persistentStoreCoordinator URLForPersistentStore:persistentStore]; + BOOL success = [self.persistentStoreCoordinator removePersistentStore:persistentStore error:&localError]; + if (success) { + if ([URL isFileURL]) { + if (! [[NSFileManager defaultManager] removeItemAtURL:URL error:&localError]) { + RKLogError(@"Failed to remove persistent store at URL %@: %@", URL, localError); + if (error) *error = localError; + return NO; + } + + // Check for and remove an external storage directory + NSString *supportDirectoryName = [NSString stringWithFormat:@".%@_SUPPORT", [[URL lastPathComponent] stringByDeletingPathExtension]]; + NSURL *supportDirectoryFileURL = [NSURL URLWithString:supportDirectoryName relativeToURL:[URL URLByDeletingLastPathComponent]]; + BOOL isDirectory = NO; + if ([[NSFileManager defaultManager] fileExistsAtPath:[supportDirectoryFileURL path] isDirectory:&isDirectory]) { + if (isDirectory) { + if (! [[NSFileManager defaultManager] removeItemAtURL:supportDirectoryFileURL error:&localError]) { + RKLogError(@"Failed to remove persistent store Support directory at URL %@: %@", supportDirectoryFileURL, localError); + if (error) *error = localError; + return NO; + } + } else { + RKLogWarning(@"Found external support item for store at path that is not a directory: %@", [supportDirectoryFileURL path]); + } + } + + // Check for and remove -shm and -wal files + for (NSString *suffix in @[ @"-shm", @"-wal" ]) { + NSString *supportFileName = [[URL lastPathComponent] stringByAppendingString:suffix]; + NSURL *supportFileURL = [NSURL URLWithString:supportFileName relativeToURL:[URL URLByDeletingLastPathComponent]]; + if ([[NSFileManager defaultManager] fileExistsAtPath:[supportFileURL path]]) { + if (! [[NSFileManager defaultManager] removeItemAtURL:supportFileURL error:&localError]) { + RKLogError(@"Failed to remove support file at URL %@: %@", supportFileURL, localError); + if (error) *error = localError; + return NO; + } + } + } + } else { + RKLogDebug(@"Skipped removal of persistent store file: URL for persistent store is not a file URL. (%@)", URL); + } + + NSPersistentStore *newStore; + if ([persistentStore.type isEqualToString:NSSQLiteStoreType]) { + // Seed path for reclone the persistent store from the seed path if necessary + NSString *seedPath = [persistentStore.options valueForKey:RKSQLitePersistentStoreSeedDatabasePathOption]; + if ([seedPath isEqual:[NSNull null]]) { + seedPath = nil; + } + + // Add a new store with the same options, except RKSQLitePersistentStoreSeedDatabasePathOption option + // that is not expected in this method. + NSMutableDictionary *mutableOptions = [persistentStore.options mutableCopy]; + [mutableOptions removeObjectForKey:RKSQLitePersistentStoreSeedDatabasePathOption]; + mutableOptions = [mutableOptions count] > 0 ? mutableOptions : nil; + // This method is only for NSSQLiteStoreType + newStore = [self addSQLitePersistentStoreAtPath:[persistentStore.URL path] + fromSeedDatabaseAtPath:seedPath + withConfiguration:persistentStore.configurationName + options:mutableOptions + error:&localError]; + } + else { + // Add a new store with the same options + newStore = [self.persistentStoreCoordinator addPersistentStoreWithType:persistentStore.type + configuration:persistentStore.configurationName + URL:persistentStore.URL + options:persistentStore.options error:&localError]; + + } + + + if (! newStore) { + if (error) *error = localError; + return NO; + } + } else { + RKLogError(@"Failed reset of persistent store %@: Failed to remove persistent store with error: %@", persistentStore, localError); + if (error) *error = localError; + return NO; + } + } + + [self recreateManagedObjectContexts]; + + [[NSNotificationCenter defaultCenter] postNotificationName:RKManagedObjectStoreDidResetPersistentStoresNotification object:self]; + + return YES; +} + ++ (BOOL)migratePersistentStoreOfType:(NSString *)storeType + atURL:(NSURL *)storeURL + toModelAtURL:(NSURL *)destinationModelURL + error:(NSError **)error + configuringModelsWithBlock:(void (^)(NSManagedObjectModel *, NSURL *))block +{ + BOOL isMomd = [[destinationModelURL pathExtension] isEqualToString:@"momd"]; // Momd contains a directory of versioned models + NSManagedObjectModel *destinationModel = [[[NSManagedObjectModel alloc] initWithContentsOfURL:destinationModelURL] mutableCopy]; + + // Yield the destination model for configuration (i.e. search indexing) + if (block) block(destinationModel, destinationModelURL); + + // Check if the store is compatible with our model + NSDictionary *storeMetadata = [NSPersistentStoreCoordinator metadataForPersistentStoreOfType:NSSQLiteStoreType + URL:storeURL + error:error]; + if (! storeMetadata) return NO; + if ([destinationModel isConfiguration:nil compatibleWithStoreMetadata:storeMetadata]) { + // Our store is compatible with the current model, no migration is necessary + return YES; + } + + RKLogInfo(@"Determined that store at URL %@ has incompatible metadata for managed object model: performing migration...", storeURL); + + NSURL *momdURL = isMomd ? destinationModelURL : [destinationModelURL URLByDeletingLastPathComponent]; + + // We can only do migrations within a versioned momd + if (![[momdURL pathExtension] isEqualToString:@"momd"]) { + NSString *errorDescription = [NSString stringWithFormat:@"Migration failed: Migrations can only be performed to versioned destination models contained in a .momd package. Incompatible destination model given at path '%@'", [momdURL path]]; + if (error) *error = [NSError errorWithDomain:RKErrorDomain code:NSMigrationError userInfo:@{ NSLocalizedDescriptionKey: errorDescription }]; + return NO; + } + + NSArray *versionedModelURLs = [[NSFileManager defaultManager] contentsOfDirectoryAtURL:momdURL + includingPropertiesForKeys:@[] // We only want the URLs + options:NSDirectoryEnumerationSkipsPackageDescendants|NSDirectoryEnumerationSkipsHiddenFiles + error:error]; + if (! versionedModelURLs) { + return NO; + } + + // Iterate across each model version and try to find a compatible store + NSManagedObjectModel *sourceModel = nil; + for (NSURL *versionedModelURL in versionedModelURLs) { + if (! [@[@"mom", @"momd"] containsObject:[versionedModelURL pathExtension]]) continue; + NSManagedObjectModel *model = [[[NSManagedObjectModel alloc] initWithContentsOfURL:versionedModelURL] mutableCopy]; + if (! model) continue; + if (block) block(model, versionedModelURL); + + if ([model isConfiguration:nil compatibleWithStoreMetadata:storeMetadata]) { + sourceModel = model; + break; + } + } + + // Cannot complete the migration as we can't find a source model + if (! sourceModel) { + NSString *errorDescription = [NSString stringWithFormat:@"Migration failed: Unable to find the source managed object model used to create the %@ store at path '%@'", storeType, [storeURL path]]; + if (error) *error = [NSError errorWithDomain:RKErrorDomain code:NSMigrationMissingSourceModelError userInfo:@{ NSLocalizedDescriptionKey: errorDescription }]; + return NO; + } + + // Infer a mapping model and complete the migration + NSMappingModel *mappingModel = [NSMappingModel inferredMappingModelForSourceModel:sourceModel + destinationModel:destinationModel + error:error]; + if (!mappingModel) { + RKLogError(@"Failed to obtain inferred mapping model for source and destination models: aborting migration..."); + RKLogError(@"%@", *error); + return NO; + } + + CFUUIDRef uuid = CFUUIDCreate(kCFAllocatorDefault); + NSString *UUID = (__bridge_transfer NSString*)CFUUIDCreateString(kCFAllocatorDefault, uuid); + CFRelease(uuid); + + NSString *migrationPath = [NSTemporaryDirectory() stringByAppendingFormat:@"Migration-%@.sqlite", UUID]; + NSURL *migrationURL = [NSURL fileURLWithPath:migrationPath]; + + // Create a migration manager to perform the migration. + NSMigrationManager *manager = [[NSMigrationManager alloc] initWithSourceModel:sourceModel destinationModel:destinationModel]; + BOOL success = [manager migrateStoreFromURL:storeURL type:NSSQLiteStoreType + options:nil withMappingModel:mappingModel toDestinationURL:migrationURL + destinationType:NSSQLiteStoreType destinationOptions:nil error:error]; + + if (success) { + success = [[NSFileManager defaultManager] removeItemAtURL:storeURL error:error]; + if (success) { + success = [[NSFileManager defaultManager] moveItemAtURL:migrationURL toURL:storeURL error:error]; + if (success) RKLogInfo(@"Successfully migrated existing store to managed object model at path '%@'...", [destinationModelURL path]); + } else { + RKLogError(@"Failed to remove existing store at path '%@': unable to complete migration...", [storeURL path]); + RKLogError(@"%@", *error); + } + } else { + RKLogError(@"Failed migration with error: %@", *error); + } + return success; +} + +@end diff --git a/Pods/RestKit/Code/CoreData/RKPropertyInspector+CoreData.h b/Pods/RestKit/Code/CoreData/RKPropertyInspector+CoreData.h new file mode 100644 index 0000000..2afbc8d --- /dev/null +++ b/Pods/RestKit/Code/CoreData/RKPropertyInspector+CoreData.h @@ -0,0 +1,45 @@ +// +// RKPropertyInspector+CoreData.h +// RestKit +// +// Created by Blake Watters on 8/14/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKPropertyInspector.h" + +/** + The `CoreData` category augments the `RKPropertyInspector` class with support for introspecting the property types for `NSManagedObject` and `NSEntityDescription` objects. + */ +@interface RKPropertyInspector (CoreData) + +/** + Returns a dictionary wherein the keys are the names of attribute and relationship properties and the values are the class used to represent the corresponding property for a given entity. + + @param entity The entity to retrieve the properties names and classes of. + @return A dictionary containing the names and classes of the given entity. + */ +- (NSDictionary *)propertyInspectionForEntity:(NSEntityDescription *)entity; + +/** + Returns the class used to represent the property with the given name on the given entity. + + @param propertyName The name of the property to retrieve the class for. + @param entity The entity containing the property to retrieve the class for. + @return The class used to represent the property. + */ +- (Class)classForPropertyNamed:(NSString *)propertyName ofEntity:(NSEntityDescription *)entity; + +@end diff --git a/Pods/RestKit/Code/CoreData/RKPropertyInspector+CoreData.m b/Pods/RestKit/Code/CoreData/RKPropertyInspector+CoreData.m new file mode 100644 index 0000000..3716dea --- /dev/null +++ b/Pods/RestKit/Code/CoreData/RKPropertyInspector+CoreData.m @@ -0,0 +1,161 @@ +// +// RKPropertyInspector+CoreData.m +// RestKit +// +// Created by Blake Watters on 8/14/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import +#import +#import "RKPropertyInspector+CoreData.h" +#import "RKLog.h" +#import "RKObjectUtilities.h" +#import "RKMacros.h" + +// Set Logging Component +#undef RKLogComponent +#define RKLogComponent RKlcl_cRestKitCoreData + +@interface RKPropertyInspector () +@property (nonatomic, assign) dispatch_queue_t queue; +@property (nonatomic, strong) NSMutableDictionary *inspectionCache; +@end + +@implementation RKPropertyInspector (CoreData) + +- (NSDictionary *)propertyInspectionForEntity:(NSEntityDescription *)entity +{ + __block NSMutableDictionary *entityInspection; + dispatch_sync(self.queue, ^{ + entityInspection = (self.inspectionCache)[[entity name]]; + }); + if (entityInspection) return entityInspection; + + entityInspection = [NSMutableDictionary dictionary]; + for (NSString *name in [entity attributesByName]) { + NSAttributeDescription *attributeDescription = [[entity attributesByName] valueForKey:name]; + if ([attributeDescription attributeValueClassName]) { + Class cls = NSClassFromString([attributeDescription attributeValueClassName]); + if ([cls isSubclassOfClass:[NSNumber class]] && [attributeDescription attributeType] == NSBooleanAttributeType) { + cls = objc_getClass("NSCFBoolean") ?: objc_getClass("__NSCFBoolean") ?: cls; + } + RKPropertyInspectorPropertyInfo *info; + info = [RKPropertyInspectorPropertyInfo propertyInfoWithName:name + keyValueClass:cls + isPrimitive:NO]; + [entityInspection setValue:info forKey:name]; + + } else if ([attributeDescription attributeType] == NSTransformableAttributeType && + ![name isEqualToString:@"_mapkit_hasPanoramaID"]) { + + const char *className = [[entity managedObjectClassName] cStringUsingEncoding:NSUTF8StringEncoding]; + const char *propertyName = [name cStringUsingEncoding:NSUTF8StringEncoding]; + Class managedObjectClass = objc_getClass(className); + + objc_property_t prop = class_getProperty(managedObjectClass, propertyName); + + // Property is not defined in the Core Data model -- we cannot infer any details about the destination type + if (prop) { + const char *attr = property_getAttributes(prop); + Class destinationClass = RKKeyValueCodingClassFromPropertyAttributes(attr); + if (destinationClass) { + RKPropertyInspectorPropertyInfo *info; + info = [RKPropertyInspectorPropertyInfo propertyInfoWithName:name + keyValueClass:destinationClass + isPrimitive:NO]; + entityInspection[name] = info; + } + } + } + } + + for (NSString *name in [entity relationshipsByName]) { + NSRelationshipDescription *relationshipDescription = [[entity relationshipsByName] valueForKey:name]; + if ([relationshipDescription isToMany]) { + if ([relationshipDescription isOrdered]) { + RKPropertyInspectorPropertyInfo *info; + info = [RKPropertyInspectorPropertyInfo propertyInfoWithName:name + keyValueClass:[NSOrderedSet class] + isPrimitive:NO]; + entityInspection[name] = info; + } else { + RKPropertyInspectorPropertyInfo *info; + info = [RKPropertyInspectorPropertyInfo propertyInfoWithName:name + keyValueClass:[NSSet class] + isPrimitive:NO]; + entityInspection[name] = info; + } + } else { + NSEntityDescription *destinationEntity = [relationshipDescription destinationEntity]; + Class destinationClass = NSClassFromString([destinationEntity managedObjectClassName]); + if (! destinationClass) { + RKLogWarning(@"Retrieved `Nil` value for class named '%@': This likely indicates that the class is invalid or does not exist in the current target.", [destinationEntity managedObjectClassName]); + } + RKPropertyInspectorPropertyInfo *info; + info = [RKPropertyInspectorPropertyInfo propertyInfoWithName:name + keyValueClass:destinationClass ?: [NSNull null] + isPrimitive:NO]; + entityInspection[name] = info; + } + } + + dispatch_barrier_async(self.queue, ^{ + (self.inspectionCache)[[entity name]] = entityInspection; + RKLogDebug(@"Cached property inspection for Entity '%@': %@", entity, entityInspection); + }); + return entityInspection; +} + +- (Class)classForPropertyNamed:(NSString *)propertyName ofEntity:(NSEntityDescription *)entity +{ + NSDictionary *entityInspection = [self propertyInspectionForEntity:entity]; + RKPropertyInspectorPropertyInfo *propertyInspection = entityInspection[propertyName]; + return propertyInspection.keyValueCodingClass; +} + +@end + +@interface NSManagedObject (RKPropertyInspection) +- (Class)rk_classForPropertyAtKeyPath:(NSString *)keyPath isPrimitive:(BOOL *)isPrimitive; +@end + +@implementation NSManagedObject (RKPropertyInspection) + +- (Class)rk_classForPropertyAtKeyPath:(NSString *)keyPath isPrimitive:(BOOL *)isPrimitive +{ + NSRange dotRange = [keyPath rangeOfString:@"." options:NSLiteralSearch]; + RKPropertyInspector *inspector = [RKPropertyInspector sharedInspector]; + Class currentPropertyClass = [self class]; + Class propertyClass = nil; + + if (dotRange.length == 0) { + propertyClass = [inspector classForPropertyNamed:keyPath ofEntity:[self entity]]; + return propertyClass ?: [inspector classForPropertyNamed:keyPath ofClass:currentPropertyClass isPrimitive:isPrimitive]; + } + + NSArray *components = [keyPath componentsSeparatedByString:@"."]; + for (NSString *property in components) { + if (isPrimitive) *isPrimitive = NO; // Core Data does not enable you to model primitives + propertyClass = [inspector classForPropertyNamed:property ofEntity:[self entity]]; + propertyClass = propertyClass ?: [inspector classForPropertyNamed:property ofClass:currentPropertyClass isPrimitive:isPrimitive]; + if (! propertyClass) break; + currentPropertyClass = propertyClass; + } + + return propertyClass; +} + +@end diff --git a/Pods/RestKit/Code/CoreData/RKRelationshipConnectionOperation.h b/Pods/RestKit/Code/CoreData/RKRelationshipConnectionOperation.h new file mode 100644 index 0000000..3dbdef6 --- /dev/null +++ b/Pods/RestKit/Code/CoreData/RKRelationshipConnectionOperation.h @@ -0,0 +1,90 @@ +// +// RKRelationshipConnectionOperation.h +// RestKit +// +// Created by Blake Watters on 7/12/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import + +@class RKConnectionDescription; +@protocol RKManagedObjectCaching; + +/** + The `RKRelationshipConnectionOperation` class is a subclass of `NSOperation` that manages the connection of `NSManagedObject` relationships as described by an `RKConnectionDescription` object. When executed, the operation will find related objects by searching the associated managed object cache for objects matching the connection description and setting them as the value for the relationship being connected. + + For example, given a managed object for the `Employee` entity with a one-to-one relationship to a `Company` named `company` (with an inverse relationship one-to-many relationship named `employees`) and a connection specifying that the relationship can be connected by finding the `Company` managed object whose `companyID` attribute matches the `companyID` of the `Employee`, the operation would find the Company that employs the Employee by primary key and set the Core Data relationship to reflect the relationship appropriately. + + @see `RKConnectionDescription` + */ +@interface RKRelationshipConnectionOperation : NSOperation + +///------------------------------------------------------- +/// @name Initializing a Relationship Connection Operation +///------------------------------------------------------- + +/** + Initializes the receiver with a given managed object, connection mapping, and managed object cache. + + @param managedObject The object to attempt to connect a relationship to. + @param connections An array of connection objects describing how establish a Core Data relationship between objects. + @param managedObjectCache The managed object cache from which to attempt to fetch a matching object to satisfy the connection. + @return The receiver, initialized with the given managed object, connection mapping, and managed object cache. + */ +- (instancetype)initWithManagedObject:(NSManagedObject *)managedObject + connections:(NSArray *)connections + managedObjectCache:(id)managedObjectCache; + +///-------------------------------------------- +/// @name Accessing Details About the Operation +///-------------------------------------------- + +/** + The managed object the receiver will attempt to connect a relationship for. + */ +@property (nonatomic, strong, readonly) NSManagedObject *managedObject; + +/** + An array of `RKConnectionDescription` objects describing the relationship connection the receiver will attempt to connect. + */ +@property (nonatomic, strong, readonly) NSArray *connections; + +/** + The managed object cache the receiver will use to fetch a related object satisfying the connection mapping. + */ +@property (nonatomic, strong, readonly) id managedObjectCache; + +/** + A dictionary keyed by the name of each relationship that was established by the receiver wherein each value is the objects or objects that were connected. + + For each key in the dictionary, the value will either be `[NSNull null]`, indicating that the relationship could not be connected, a single `NSManagedObject` object (if the relationship is one-to-one), or an array of `NSManagedObject` objects (if the relationship is one-to-many). + */ +@property (nonatomic, strong, readonly) NSDictionary *connectedValuesByRelationshipName; + +///----------------------------------- +/// @name Setting the Connection Block +///----------------------------------- + +/** + Sets a block to be executed on the operation attempted to establish the connection. + + Unlike the block set with `setCompletionBlock:`, this block is executed during the body of the operation within the queue of the managed object context in which the connection was established. This means that it is safe to executed both the `connectedValue` and `managedObject` directly within the body of the block. + + @param block A block object to be executed when the connection is evaluated. The block accepts two arguments: the operation itself and the value, if any, that was set for the relationship targetted by the connection description. + */ +- (void)setConnectionBlock:(void (^)(RKRelationshipConnectionOperation *operation, RKConnectionDescription *connection, id connectedValue))block; + +@end diff --git a/Pods/RestKit/Code/CoreData/RKRelationshipConnectionOperation.m b/Pods/RestKit/Code/CoreData/RKRelationshipConnectionOperation.m new file mode 100644 index 0000000..5cba533 --- /dev/null +++ b/Pods/RestKit/Code/CoreData/RKRelationshipConnectionOperation.m @@ -0,0 +1,237 @@ +// +// RKRelationshipConnectionOperation.m +// RestKit +// +// Created by Blake Watters on 7/12/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import +#import "RKRelationshipConnectionOperation.h" +#import "RKConnectionDescription.h" +#import "RKEntityMapping.h" +#import "RKLog.h" +#import "RKManagedObjectCaching.h" +#import "RKObjectMappingMatcher.h" +#import "RKErrors.h" +#import "RKObjectUtilities.h" + +// Set Logging Component +#undef RKLogComponent +#define RKLogComponent RKlcl_cRestKitCoreData + +id RKMutableSetValueForRelationship(NSRelationshipDescription *relationship); +id RKMutableSetValueForRelationship(NSRelationshipDescription *relationship) +{ + if (! [relationship isToMany]) return nil; + return [relationship isOrdered] ? [NSMutableOrderedSet orderedSet] : [NSMutableSet set]; +} + +static BOOL RKConnectionAttributeValuesIsNotConnectable(NSDictionary *attributeValues) +{ + return [[NSSet setWithArray:[attributeValues allValues]] isEqualToSet:[NSSet setWithObject:[NSNull null]]]; +} + +static NSDictionary *RKConnectionAttributeValuesWithObject(RKConnectionDescription *connection, NSManagedObject *managedObject) +{ + NSCAssert([connection isForeignKeyConnection], @"Only valid for a foreign key connection"); + NSMutableDictionary *destinationEntityAttributeValues = [NSMutableDictionary dictionaryWithCapacity:[connection.attributes count]]; + [managedObject.managedObjectContext performBlockAndWait:^{ + for (NSString *sourceAttribute in connection.attributes) { + NSString *destinationAttribute = (connection.attributes)[sourceAttribute]; + id sourceValue = [managedObject valueForKey:sourceAttribute]; + [destinationEntityAttributeValues setValue:sourceValue ?: [NSNull null] forKey:destinationAttribute]; + } + }]; + return RKConnectionAttributeValuesIsNotConnectable(destinationEntityAttributeValues) ? nil : destinationEntityAttributeValues; +} + +@interface RKRelationshipConnectionOperation () +@property (nonatomic, strong, readwrite) NSManagedObject *managedObject; +@property (nonatomic, strong, readwrite) NSArray *connections; +@property (nonatomic, strong, readwrite) id managedObjectCache; +@property (nonatomic, strong, readwrite) NSError *error; +@property (nonatomic, strong, readwrite) NSMutableDictionary *connectedValuesByRelationshipName; +@property (nonatomic, copy) void (^connectionBlock)(RKRelationshipConnectionOperation *operation, RKConnectionDescription *connection, id connectedValue); + +// Helpers +@property (weak, nonatomic, readonly) NSManagedObjectContext *managedObjectContext; + +@end + +@implementation RKRelationshipConnectionOperation + +- (instancetype)initWithManagedObject:(NSManagedObject *)managedObject + connections:(NSArray *)connections + managedObjectCache:(id)managedObjectCache +{ + NSParameterAssert(managedObject); + NSAssert([managedObject isKindOfClass:[NSManagedObject class]], @"Relationship connection requires an instance of NSManagedObject"); + NSParameterAssert(connections); + NSParameterAssert(managedObjectCache); + self = [self init]; + if (self) { + self.managedObject = managedObject; + self.connections = connections; + self.managedObjectCache = managedObjectCache; + } + + return self; +} + +- (NSManagedObjectContext *)managedObjectContext +{ + return self.managedObject.managedObjectContext; +} + +- (id)relationshipValueForConnection:(RKConnectionDescription *)connection withConnectionResult:(id)result +{ + // TODO: Replace with use of object mapping engine for type conversion + + // NOTE: This is a nasty hack to work around the fact that NSOrderedSet does not support key-value + // collection operators. We try to detect and unpack a doubly wrapped collection + if ([connection.relationship isToMany] && RKObjectIsCollectionOfCollections(result)) { + id mutableSet = RKMutableSetValueForRelationship(connection.relationship); + for (id enumerable in result) { + for (id object in enumerable) { + [mutableSet addObject:object]; + } + } + + return mutableSet; + } + + if ([connection.relationship isToMany]) { + if ([result isKindOfClass:[NSArray class]]) { + if ([connection.relationship isOrdered]) { + return [NSOrderedSet orderedSetWithArray:result]; + } else { + return [NSSet setWithArray:result]; + } + } else if ([result isKindOfClass:[NSSet class]]) { + if ([connection.relationship isOrdered]) { + return [NSOrderedSet orderedSetWithSet:result]; + } else { + return result; + } + } else if ([result isKindOfClass:[NSOrderedSet class]]) { + if ([connection.relationship isOrdered]) { + return result; + } else { + return [(NSOrderedSet *)result set]; + } + } else { + if ([connection.relationship isOrdered]) { + return [NSOrderedSet orderedSetWithObject:result]; + } else { + return [NSSet setWithObject:result]; + } + } + } + + return result; +} + +- (id)findConnectedValueForConnection:(RKConnectionDescription *)connection shouldConnect:(BOOL *)shouldConnectRelationship +{ + *shouldConnectRelationship = YES; + id connectionResult = nil; + if (connection.sourcePredicate) { + __block BOOL evaluationResult; + [self.managedObject.managedObjectContext performBlockAndWait:^{ + evaluationResult = [connection.sourcePredicate evaluateWithObject:self.managedObject]; + }]; + + if (!evaluationResult) return nil; + } + + if ([connection isForeignKeyConnection]) { + NSDictionary *attributeValues = RKConnectionAttributeValuesWithObject(connection, self.managedObject); + // If there are no attribute values available for connecting, skip the connection entirely + if (! attributeValues) { + *shouldConnectRelationship = NO; + return nil; + } + __block NSSet *managedObjects = [self.managedObjectCache managedObjectsWithEntity:[connection.relationship destinationEntity] + attributeValues:attributeValues + inManagedObjectContext:self.managedObjectContext]; + + [self.managedObjectContext performBlockAndWait:^{ + if (connection.destinationPredicate) managedObjects = [managedObjects filteredSetUsingPredicate:connection.destinationPredicate]; + if (!connection.includesSubentities) managedObjects = [managedObjects filteredSetUsingPredicate:[NSPredicate predicateWithFormat:@"entity == %@", [connection.relationship destinationEntity]]]; + }]; + + if ([connection.relationship isToMany]) { + connectionResult = managedObjects; + } else { + if ([managedObjects count] > 1) RKLogWarning(@"Retrieved %ld objects satisfying connection criteria for one-to-one relationship connection: only one object will be connected.", (long) [managedObjects count]); + if ([managedObjects count]) connectionResult = [managedObjects anyObject]; + } + } else if ([connection isKeyPathConnection]) { + connectionResult = [self.managedObject valueForKeyPath:connection.keyPath]; + } else { + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:[NSString stringWithFormat:@"%@ Attempted to establish a relationship using a mapping that" + " specifies neither a foreign key or a key path connection: %@", + NSStringFromClass([self class]), connection] + userInfo:nil]; + } + + return [self relationshipValueForConnection:connection withConnectionResult:connectionResult]; +} + +- (void)main +{ + for (RKConnectionDescription *connection in self.connections) { + __block BOOL isDeleted; + [self.managedObject.managedObjectContext performBlockAndWait:^{ + isDeleted=[self.managedObject isDeleted]; + }]; + if (self.isCancelled || isDeleted) return; + NSString *relationshipName = connection.relationship.name; + RKLogTrace(@"Connecting relationship '%@' with mapping: %@", relationshipName, connection); + + BOOL shouldConnect = YES; + // TODO: What I need to do is make all of this based on callbacks so I can jump in/out of the MOC queue + id connectedValue = [self findConnectedValueForConnection:connection shouldConnect:&shouldConnect]; + [self.connectedValuesByRelationshipName setValue:(connectedValue ?: [NSNull null]) forKey:relationshipName]; + if (shouldConnect) { + [self.managedObjectContext performBlockAndWait:^{ + if (self.isCancelled || [self.managedObject isDeleted]) return; + @try { + [self.managedObject setValue:connectedValue forKeyPath:relationshipName]; + RKLogDebug(@"Connected relationship '%@' to object '%@'", relationshipName, connectedValue); + if (self.connectionBlock) self.connectionBlock(self, connection, connectedValue); + } + @catch (NSException *exception) { + if ([[exception name] isEqualToString:NSObjectInaccessibleException]) { + // Object has been deleted + RKLogDebug(@"Rescued an `NSObjectInaccessibleException` exception while attempting to establish a relationship."); + } else { + [exception raise]; + } + } + }]; + } + } +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@"<%@:%p %@ in %@ using %@>", + [self class], self, self.connections, self.managedObjectContext, self.managedObjectCache]; +} + +@end diff --git a/Pods/RestKit/Code/Network.h b/Pods/RestKit/Code/Network.h new file mode 100644 index 0000000..53d34a5 --- /dev/null +++ b/Pods/RestKit/Code/Network.h @@ -0,0 +1,34 @@ +// +// Network.h +// RestKit +// +// Created by Blake Watters on 9/30/10. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKRoute.h" +#import "RKRouteSet.h" +#import "RKRouter.h" +#import "RKRequestDescriptor.h" +#import "RKResponseDescriptor.h" +#import "RKObjectManager.h" +#import "RKHTTPUtilities.h" +#import "RKObjectRequestOperation.h" +#import "RKObjectParameterization.h" +#import "RKPathMatcher.h" + +#ifdef _COREDATADEFINES_H +#import "RKManagedObjectRequestOperation.h" +#endif diff --git a/Pods/RestKit/Code/Network/RKHTTPRequestOperation.h b/Pods/RestKit/Code/Network/RKHTTPRequestOperation.h new file mode 100644 index 0000000..5f41c3f --- /dev/null +++ b/Pods/RestKit/Code/Network/RKHTTPRequestOperation.h @@ -0,0 +1,60 @@ +// +// RKHTTPRequestOperation.h +// RestKit +// +// Created by Blake Watters on 8/7/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import +#import + +// Expose the default headers from AFNetworking's AFHTTPClient +@interface AFHTTPClient () +@property (readonly, nonatomic) NSDictionary *defaultHeaders; +@end + +/** + The `RKHTTPRequestOperation` class is a subclass of `AFHTTPRequestOperation` for HTTP or HTTPS requests made by RestKit. It provides per-instance configuration of the acceptable status codes and content types and integrates with the `RKLog` system to provide detailed requested and response logging. Instances of `RKHTTPRequest` are created by `RKObjectRequestOperation` and its subclasses to HTTP requests that will be object mapped. When used to make standalone HTTP requests, `RKHTTPRequestOperation` instance behave identically to `AFHTTPRequestOperation` with the exception of emitting logging information. + + ## Determining Request Processability + + The `RKHTTPRequestOperation` class diverges from the behavior of `AFHTTPRequestOperation` in the implementation of `canProcessRequest`, which is used to determine if a request can be processed. Because `RKHTTPRequestOperation` handles Content Type and Status Code acceptability at the instance rather than the class level, it by default returns `YES` when sent a `canProcessRequest:` method. Subclasses are encouraged to implement more specific logic if constraining the type of requests handled is desired. + */ +@interface RKHTTPRequestOperation : AFHTTPRequestOperation + +///------------------------------------------------------------ +/// @name Configuring Acceptable Status Codes and Content Types +///------------------------------------------------------------ + +/** + The set of status codes which the operation considers successful. + + When `nil`, the acceptability of status codes is deferred to the superclass implementation. + + **Default**: `nil` + */ +@property (nonatomic, strong) NSIndexSet *acceptableStatusCodes; + +/** + The set of content types which the operation considers successful. + + The set may contain `NSString` or `NSRegularExpression` objects. When `nil`, the acceptability of content types is deferred to the superclass implementation. + + **Default**: `nil` + */ +@property (nonatomic, strong) NSSet *acceptableContentTypes; + +@end diff --git a/Pods/RestKit/Code/Network/RKHTTPRequestOperation.m b/Pods/RestKit/Code/Network/RKHTTPRequestOperation.m new file mode 100644 index 0000000..8b6f6af --- /dev/null +++ b/Pods/RestKit/Code/Network/RKHTTPRequestOperation.m @@ -0,0 +1,139 @@ +// +// RKHTTPRequestOperation.m +// RestKit +// +// Created by Blake Watters on 8/7/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKHTTPRequestOperation.h" +#import "RKLog.h" +#import "lcl_RK.h" +#import "RKHTTPUtilities.h" +#import "RKMIMETypes.h" + +extern NSString * const RKErrorDomain; + +// Set Logging Component +#undef RKLogComponent +#define RKLogComponent RKlcl_cRestKitNetwork + +NSString *RKStringFromIndexSet(NSIndexSet *indexSet); // Defined in RKResponseDescriptor.m + +static BOOL RKResponseRequiresContentTypeMatch(NSHTTPURLResponse *response, NSURLRequest *request) +{ + if (RKRequestMethodFromString(request.HTTPMethod) == RKRequestMethodHEAD) return NO; + if ([RKStatusCodesOfResponsesWithOptionalBodies() containsIndex:response.statusCode]) return NO; + return YES; +} + +@interface AFURLConnectionOperation () +@property (readwrite, nonatomic, strong) NSRecursiveLock *lock; +@end + +@interface RKHTTPRequestOperation () +@property (readwrite, nonatomic, strong) NSError *rkHTTPError; +@end + +@implementation RKHTTPRequestOperation + ++ (BOOL)canProcessRequest:(NSURLRequest *)request +{ + return YES; +} + +// Disable class level Content/Status Code inspection in our superclass ++ (NSSet *)acceptableContentTypes +{ + return nil; +} + ++ (NSIndexSet *)acceptableStatusCodes +{ + return nil; +} + +- (BOOL)hasAcceptableStatusCode +{ + if (! self.response) return NO; + NSUInteger statusCode = ([self.response isKindOfClass:[NSHTTPURLResponse class]]) ? (NSUInteger)[self.response statusCode] : 200; + return self.acceptableStatusCodes ? [self.acceptableStatusCodes containsIndex:statusCode] : [super hasAcceptableStatusCode]; +} + +- (BOOL)hasAcceptableContentType +{ + if (! self.response) return NO; + if (!RKResponseRequiresContentTypeMatch(self.response, self.request)) return YES; + NSString *contentType = [self.response MIMEType] ?: @"application/octet-stream"; + return self.acceptableContentTypes ? RKMIMETypeInSet(contentType, self.acceptableContentTypes) : [super hasAcceptableContentType]; +} + +// NOTE: We reimplement this because the AFNetworking implementation keeps Acceptable Status Code/MIME Type at class level +- (NSError *)error +{ + [self.lock lock]; + + if (!self.rkHTTPError && self.response) { + if (![self hasAcceptableStatusCode] || ![self hasAcceptableContentType]) { + NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; + [userInfo setValue:self.responseString forKey:NSLocalizedRecoverySuggestionErrorKey]; + [userInfo setValue:[self.request URL] forKey:NSURLErrorFailingURLErrorKey]; + [userInfo setValue:self.request forKey:AFNetworkingOperationFailingURLRequestErrorKey]; + [userInfo setValue:self.response forKey:AFNetworkingOperationFailingURLResponseErrorKey]; + + if (![self hasAcceptableStatusCode]) { + NSUInteger statusCode = ([self.response isKindOfClass:[NSHTTPURLResponse class]]) ? (NSUInteger)[self.response statusCode] : 200; + [userInfo setValue:[NSString stringWithFormat:NSLocalizedString(@"Expected status code in (%@), got %d", nil), RKStringFromIndexSet(self.acceptableStatusCodes ?: [NSMutableIndexSet indexSet]), statusCode] forKey:NSLocalizedDescriptionKey]; + self.rkHTTPError = [[NSError alloc] initWithDomain:RKErrorDomain code:NSURLErrorBadServerResponse userInfo:userInfo]; + } else if (![self hasAcceptableContentType] && self.response.statusCode != 204) { + // NOTE: 204 responses come back as text/plain, which we don't want + [userInfo setValue:[NSString stringWithFormat:NSLocalizedString(@"Expected content type %@, got %@", nil), self.acceptableContentTypes, [self.response MIMEType]] forKey:NSLocalizedDescriptionKey]; + self.rkHTTPError = [[NSError alloc] initWithDomain:RKErrorDomain code:NSURLErrorCannotDecodeContentData userInfo:userInfo]; + } + } + } + + NSError *error = self.rkHTTPError ?: [super error]; + [self.lock unlock]; + return error; +} + +#pragma mark - NSURLConnectionDelegate methods + +- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge +{ + [super connection:connection didReceiveAuthenticationChallenge:challenge]; + + RKLogDebug(@"Received authentication challenge"); +} + +- (NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse +{ + if ([AFHTTPRequestOperation instancesRespondToSelector:@selector(connection:willSendRequest:redirectResponse:)]) { + NSURLRequest *returnValue = [super connection:connection willSendRequest:request redirectResponse:redirectResponse]; + if (returnValue) { + if (redirectResponse) RKLogDebug(@"Following redirect request: %@", returnValue); + return returnValue; + } else { + RKLogDebug(@"Not following redirect to %@", request); + return nil; + } + } else { + if (redirectResponse) RKLogDebug(@"Following redirect request: %@", request); + return request; + } +} + +@end diff --git a/Pods/RestKit/Code/Network/RKManagedObjectRequestOperation.h b/Pods/RestKit/Code/Network/RKManagedObjectRequestOperation.h new file mode 100644 index 0000000..c677e98 --- /dev/null +++ b/Pods/RestKit/Code/Network/RKManagedObjectRequestOperation.h @@ -0,0 +1,209 @@ +// +// RKManagedObjectRequestOperation.h +// RestKit +// +// Created by Blake Watters on 8/9/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#ifdef _COREDATADEFINES_H +#if __has_include("RKManagedObjectCaching.h") + +#import "RKObjectRequestOperation.h" +#import "RKManagedObjectCaching.h" + +/** + `RKManagedObjectRequestOperation` is a subclass of `RKObjectRequestOperation` that implements object mapping on the response body of an `NSHTTPResponse` loaded via an `RKHTTPRequestOperation` in which the mapping targets `NSManagedObject` objects managed by Core Data. + + The `RKManagedObjectRequestOperation` class extends the basic behavior of an `RKObjectRequestOperation` to meet the constraints imposed by Core Data. In particular, managed object request operations observe the threading requirements by making use of `NSManagedObjectContext` concurrency types, leverage the support for parent/child contexts, and handle obtaining a permanent `NSManagedObjectID` for objects being mapped so that they are addressable across contexts. Object mapping is internally performed within a block provided to the target context via `performBlockAndWait:`, ensuring execution on the appropriate queue. + + Aside from providing the basic infrastructure for successful object mapping into Core Data, a number of additional Core Data specific features are provided by the `RKManagedObjectRequestOperation` class that warrant discussion in detail. + + ## Parent Context + + Every `RKManagedObjectRequestOperation` object must be assigned an `NSManagedObjectContext` in which to persist the results of the underlying object mapping operation. This context is used as the parent context for a new, private `NSManagedObjectContext` with a concurrency type of `NSPrivateQueueConcurrencyType` in which the object mapping is actually performed. The use of this parent context has a number of benefits: + + 1. If the context that was assigned to the managed object request operation has a concurrency type of `NSMainQueueConcurrencyType`, then directly mapping into the context would block the execution of the main thread for the duration of the mapping process. The use of the private child context isolates the mapping process from the main thread. + 1. In the event of an error, the private context can be discarded, leaving the state of the parent context unchanged. On successful completion, the private context is saved and 'pushes' its changes up one level into the parent context. + + ## Permanent Managed Object IDs + + One of the confounding factors when working with asycnhronous processes interacting with Core Data is the addressability of managed objects that have not been saved to the persistent store across contexts. Unpersisted `NSManagedObject` instances have an `objectID` that is temporary and unsuitable for use in uniquely addressing a given object across two managed object contexts, even if they have common ancestry and share a persistent store coordinator. To mitigate this addressability issue without requiring objects to be saved to the persistent store, managed object request operations invoke `obtainPermanentIDsForObjects:` on the operation's target object (if any) and all managed objects that were inserted into the context during the mapping process. By the time the operation finishes, all managed objects in the mapping result can be referenced by `objectID` across contexts with no further action. + + ## Identification Attributes & Managed Object Caching + + When object mapping managed objects it is necessary to differentiate between objects that already exist in the local store and those that are being created as part of the mapping process. This ensures that the local store does not become populated with duplicate records. To make this differentiation, RestKit requires that each `RKEntityMapping` be configured with one or more identification attributes. Each identification attribute must correspond to a static attribute assigned by the remote backend system. During mapping, these attributes are used to search the managed object context for an existing managed object. If one is found, the object is updated else a new object is created. Identification attributes are configured on the `[RKEntityMapping identificationAttributes]` property. + + Identification attributes are used in conjunction with the `RKManagedObjectCaching` protocol. Each managed object request operation is associated with an object conforming to the `RKManagedObjectCaching` protocol via the `managedObjectCache` proeprty. This cache is consulted during mapping to find existing objects and when establishing relationships between entities by one or more attributes. Please see the documentation accompanying `RKManagedObjectCaching` and `RKConnectionDescription` classes for more information. + + ## Deleting Managed Objects for `DELETE` requests + + `RKManagedObjectRequestOperation` adds special behavior to `DELETE` requests. Upon retrieving a successful (2xx status code) response for a `DELETE`, the operation will invoke `deleteObject:` with the operations `targetObject` on the managed object context. This will delete the target object from the local store in conjunction the successfully deleted remote representation. + + ## Fetch Request Blocks and Deleting Orphaned Objects + + A common problem when accessing remote resources representing collections of objects is the problem of deletion of remote objects. The `RKManagedObjectRequestOperation` class provides support for the cleanup of such orphaned objects. In order to utilize the functionality, the operation must be able to compare a set of reference objects to the retrieved payload in order to determine which objects exist in the local store, but are no longer being returned by the server. This reference set of objects is built by executing an `NSFetchRequest` that corresponds to the URL being loaded. Configuration of this fetch request is done via an `RKFetchRequestBlock` block object. This block takes a single `NSURL` argument and returns an `NSFetchRequest` object. An array of these blocks can be provided to the managed object request operation and the array will be searched in reverse order until a non-nil value is returned by a block. Any block that cannot build a fetch request for the given URL is expected to return `nil` to indicate that it does not match the given URL. Processing of the URL is typically performed using an `RKPathMatcher` object against the value returned from the `relativePath` or `relativeString` methods of `NSURL`. + + To illustrate this concept, please consider the following real-world example which builds a fetch request for retrieving the Terminals that exist in an Airport: + + RKObjectManager *manager = [RKObjectManager managerWithBaseURL:@"http://restkit.org"]; + [manager addFetchRequestBlock:^NSFetchRequest *(NSURL *URL) { + RKPathMatcher *pathMatcher = [RKPathMatcher pathMatcherWithPattern:@"/airports/:airport_id/terminals.json"]; + + NSDictionary *argsDict = nil; + BOOL match = [pathMatcher matchesPath:[URL relativePath] tokenizeQueryStrings:NO parsedArguments:&argsDict]; + NSString *airportID; + if (match) { + airportID = [argsDict objectForKey:@"airport_id"]; + NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Terminal"]; + fetchRequest.predicate = [NSPredicate predicateWithFormat:@"airportID = %@", @([airportID integerValue])]; // NOTE: Coerced from string to number + fetchRequest.sortDescriptors = @[ [NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES] ]; + return fetchRequest; + } + + return nil; + }]; + + The above example code defines an `RKFetchRequestBlock` block object that will match an `NSURL` with a relative path matching the pattern `@"/airports/:airport_id/terminals.json"`. If a match is found, the block extracts the `airport_id` key from the matched arguments, coerces its value into a number, and uses it to construct an `NSPredicate` for the primary key attribute of `GGAirport` entity. Take note that the value of the 'airport_id' was coerced from an `NSString` to an `NSNumber` -- failure to so would result in a predicate whose value is equal to `airportID == '1234'` vs. `airportID == 1234`, which will prevent fetch requests from evaluating correctly. Once coerced, the value is used to construct a `NSFetchRequest` object for the `GGTerminal` entity that will retrieve all the managed objects with an airport ID attribute whose value is equal to `airport_id` encoded within the URL's path. + + In more concrete terms, given the URL `http://restkit.org/airports/1234/terminals.json` the block would return an `NSFetchRequest` equal to: + + NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Terminal"]; + fetchRequest.predicate = [NSPredicate predicateWithFormat:@"airportID = 1234"]; + fetchRequest.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES]]; + + Once configured and registered with the object manager, any `RKManagedObjectRequestOperation` created through the manager will automatically consult the fetch request blocks and perform orphaned object cleanup. No cleanup is performed if no block in the `fetchRequestBlocks` property is found to match the URL of the request. + + ## Managed Object Context Save Behaviors + + The results of the operation can either be 'pushed' to the parent context or saved to the persistent store. Configuration is available via the `savesToPersistentStore` property. If an error is encountered while saving the managed object context, then the operation is considered to have failed and the `error` property will be set to the `NSError` object returned by the failed save. + + ## 304 'Not Modified' Responses + + In the event that a managed object request operation loads a 304 'Not Modified' response for an HTTP request no object mapping is performed as Core Data is assumed to contain a managed object representation of the resource requested. No object mapping is performed on the cached response body, making a cache hit for a managed object request operation a very lightweight operation. To build the mapping result returned to the caller, all of the fetch request blocks matching the request URL will be invoked and each fetch request returned is executed against the managed object context and the objects returned are added to the mapping result. Please note that all managed objects returned in the mapping result for a 'Not Modified' response will be returned under the `[NSNull null]` key path. + + Note that `NSURLConnection` supports conditional GET transparently when the cache policy is set to `NSURLRequestUseProtocolCachePolicy`. Because of this the `NSHTTPURLResponse` loaded does not have the 304 (Not Modified) status code. In order to determine if a 304 response has resulted in the loading of an existing response from `NSURLCache`, the managed object request operation evaluates the following heuristic on the response: + + 1. Before the HTTP request is loaded, a reference to any existing `NSCachedURLResponse` is obtained. + 1. When the response is loaded, the request is evaluated for cacheability. A request is considered cacheable if and only if its HTTP method is either "GET" or "HEAD" and its status code is 200, 304, 203, 300, 301, 302, 307, or 410. + 1. If the request is found to be cacheable, the Etag of the current response is matched against the reference to the existing cache entry obtained before the request was loaded. + 1. If the Etags match, the response data of the loaded response is matched against the cache entry reference. + 1. If the data is found to match, then the `userInfo` dictionary of the cache entry for the current request is checked for the existence of Boolean value under the `RKResponseHasBeenMappedCacheUserInfoKey` key. If the value of this key is `YES`, it indicates that the response was previously mapped to completion by an object request operation. + + If this heuristic evaluates positively, then the response is determined to have been loaded from the cache and no mapping or managed object deletion cleanup is performed. This optimization greatly improves performance in applications where HTTP caching is leveraged. + + ## Subclassing Notes + + This class relies on the following `RKMapperOperationDelegate` method methods to do its work: + + 1. `mapperDidFinishMapping:` + + If you subclass `RKManagedObjectRequestOperation` and implement any of the above methods then you must call the superclass implementation. + + ## Limitations and Caveats + + 1. `RKManagedObjectRequestOperation` **does NOT** support object mapping that targets an `NSManagedObjectContext` with a `concurrencyType` of `NSConfinementConcurrencyType`. + + @see `RKObjectRequestOperation` + @see `RKEntityMapping` + @see `RKManagedObjectResponseMapperOperation` + */ +@interface RKManagedObjectRequestOperation : RKObjectRequestOperation + +///---------------------------------------- +/// @name Configuring Core Data Integration +///---------------------------------------- + +/** + The managed object context associated with the managed object request operation. + + This context acts as the parent context for a private managed object context in which the object mapping is performed and changes will be saved to this context upon successful completion of the operation. + + Please see the above discussion about 'Parent Context' for details. + */ +@property (nonatomic, strong) NSManagedObjectContext *managedObjectContext; + +/** + The managed object cache associated with the managed object request operation. + + The cache is used to look up existing objects by primary key to prevent the creation of duplicate objects during mapping. Please see the above discussion of 'Managed Object Caching' for more details. + + @warning A `nil` value for the `managedObjectCache` property is valid, but may result in the creation of duplicate objects. + */ +@property (nonatomic, strong) id managedObjectCache; + +/** + An array of `RKFetchRequestBlock` block objects used to map `NSURL` objects into corresponding `NSFetchRequest` objects. + + Fetch requests corresponding to URL's are used when deleting orphaned objects and completing object request operations in which `avoidsNetworkAccess` has been set to `YES`. Please see the above discussion of 'Fetch Request Blocks' for more details. + */ +@property (nonatomic, copy) NSArray *fetchRequestBlocks; + +///------------------------------------ +/// @name Managing Completion Behaviors +///------------------------------------ + +/** + A Boolean value that determines if the receiver will delete orphaned objects upon completion of the operation. + + Please see the above discussion of 'Deleting Managed Objects for `DELETE` requests' for more details. + + **Default**: `YES` + */ +@property (nonatomic, assign) BOOL deletesOrphanedObjects; + +/** + A Boolean value that determines if the operation saves the mapping results to the persistent store upon successful completion. If the network transport or mapping portions of the operation fail the operation then this option has no effect. + + When `YES`, the receiver will invoke `saveToPersistentStore:` on its private managed object context to persist the mapping results all the way back to the persistent store coordinator. If `NO`, the private mapping context will be saved causing the mapped objects to be 'pushed' to the parent context as represented by the `managedObjectContext` property. + + **Default**: `YES` + */ +@property (nonatomic, assign) BOOL savesToPersistentStore; + +/** + Sets a block to be invoked just before the operation saves the private mapping context. + + The mapping context is saved just before the object request operation completes its work and transitions into the finished state. All managed objects mapped during the operation will have permanent object ID's. The `mappingResult` will contain managed object instances local to the context yielded to the block. The block will be invoked synchronously on the private queue of the context. After the block is executed, the save operation will take place, optionally saving the mapping results back to the persistent store. + + @param block The block to execute just before the context is saved. + */ +- (void)setWillSaveMappingContextBlock:(void (^)(NSManagedObjectContext *mappingContext))block; + +@end + +/** + A block object for returning an `NSFetchRequest` suitable for fetching the managed objects that corresponds to the contents of the resource at the given URL. It accepts a single `NSURL` argument and returns an `NSFetchRequest`. + + `RKFetchRequestBlock` objects are used to identify objects that exist in the local persistent store, but have been removed from the server-side. Such orphaned objects can optionally be auto-removed by `RKManagedObjectRequestOperation` objects. + + A block that returns `nil` is considered not to match the given URL. + + @param URL The URL object to build a fetch request for. + @return An `NSFetchRequest` object corresponding to the given URL, or nil if the URL could not be processed. + */ +typedef NSFetchRequest *(^RKFetchRequestBlock)(NSURL *URL); + +/** + Returns an array of fetch request objects from an array of `RKFetchRequestBlock` objects given a URL. + + @param fetchRequestBlocks An array of `RKFetchRequestBlock` blocks to + @param URL The URL for which to return a fetch request. + @return An array of fetch requests from all blocks that match the given URL. + */ +NSArray *RKArrayOfFetchRequestFromBlocksWithURL(NSArray *fetchRequestBlocks, NSURL *URL); + +#endif +#endif diff --git a/Pods/RestKit/Code/Network/RKManagedObjectRequestOperation.m b/Pods/RestKit/Code/Network/RKManagedObjectRequestOperation.m new file mode 100644 index 0000000..df3ff6c --- /dev/null +++ b/Pods/RestKit/Code/Network/RKManagedObjectRequestOperation.m @@ -0,0 +1,924 @@ +// +// RKManagedObjectRequestOperation.m +// RestKit +// +// Created by Blake Watters on 8/9/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#ifdef _COREDATADEFINES_H +#if __has_include("RKManagedObjectCaching.h") + +#import "RKManagedObjectRequestOperation.h" +#import "RKLog.h" +#import "RKHTTPUtilities.h" +#import "RKResponseMapperOperation.h" +#import "RKObjectRequestOperationSubclass.h" +#import "NSManagedObjectContext+RKAdditions.h" +#import "NSManagedObject+RKAdditions.h" +#import "RKObjectUtilities.h" + +// Graph visitor +#import "RKResponseDescriptor.h" +#import "RKEntityMapping.h" +#import "RKDynamicMapping.h" +#import "RKRelationshipMapping.h" + +// Set Logging Component +#undef RKLogComponent +#define RKLogComponent RKlcl_cRestKitNetworkCoreData + +@interface RKEntityMappingEvent : NSObject +@property (nonatomic, copy) id rootKey; +@property (nonatomic, copy) NSString *keyPath; +@property (nonatomic, strong) RKEntityMapping *entityMapping; + ++ (NSArray *)entityMappingEventsForMappingInfo:(NSDictionary *)mappingInfo; ++ (instancetype)eventWithRootKey:(id)rootKey keyPath:(NSString *)keyPath entityMapping:(RKEntityMapping *)entityMapping; +@end + +@implementation RKEntityMappingEvent + ++ (NSArray *)entityMappingEventsForMappingInfo:(NSDictionary *)mappingInfo +{ + NSMutableArray *entityMappingEvents = [NSMutableArray array]; + for (id rootKey in mappingInfo) { + NSArray *mappingInfoArray = mappingInfo[rootKey]; + for (RKMappingInfo *mappingInfo in mappingInfoArray) { + [entityMappingEvents addObjectsFromArray:[self entityMappingEventsWithMappingInfo:mappingInfo rootKey:rootKey keyPath:nil]]; + } + } + return entityMappingEvents; +} + ++ (NSArray *)entityMappingEventsWithMappingInfo:(RKMappingInfo *)mappingInfo rootKey:(id)rootKey keyPath:(NSString *)keyPath +{ + NSMutableArray *entityMappingEvents = [NSMutableArray array]; + if ([mappingInfo.objectMapping isKindOfClass:[RKEntityMapping class]]) { + [entityMappingEvents addObject:[RKEntityMappingEvent eventWithRootKey:rootKey + keyPath:keyPath + entityMapping:(RKEntityMapping *)mappingInfo.objectMapping]]; + } + + for (NSString *destinationKeyPath in mappingInfo.relationshipMappingInfo) { + NSString *nestedKeyPath = keyPath ? [@[ keyPath, destinationKeyPath] componentsJoinedByString:@"."] : destinationKeyPath; + NSArray *arrayOfMappingInfoForRelationship = (mappingInfo.relationshipMappingInfo)[destinationKeyPath]; + for (RKMappingInfo *mappingInfo in arrayOfMappingInfoForRelationship) { + [entityMappingEvents addObjectsFromArray:[self entityMappingEventsWithMappingInfo:mappingInfo rootKey:rootKey keyPath:nestedKeyPath]]; + } + } + return entityMappingEvents; +} + ++ (instancetype)eventWithRootKey:(id)rootKey keyPath:(NSString *)keyPath entityMapping:(RKEntityMapping *)entityMapping +{ + RKEntityMappingEvent *event = [RKEntityMappingEvent new]; + event.rootKey = rootKey; + event.keyPath = keyPath; + event.entityMapping = entityMapping; + return event; +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@"<%@: %p rootKey=%@ keyPath=%@ entityMapping=%@>", + [self class], self, self.rootKey, self.keyPath, self.entityMapping]; +} +@end + +/** + Returns the set of keys containing the outermost nesting keypath for all children. + For example, given a set containing: 'this', 'this.that', 'another.one.test', 'another.two.test', 'another.one.test.nested' + would return: 'this, 'another.one', 'another.two' + */ +NSSet *RKSetByRemovingSubkeypathsFromSet(NSSet *setOfKeyPaths); +NSSet *RKSetByRemovingSubkeypathsFromSet(NSSet *setOfKeyPaths) +{ + return [setOfKeyPaths objectsPassingTest:^BOOL(NSString *keyPath, BOOL *stop) { + if ([keyPath isEqual:[NSNull null]]) return YES; // Special case the root key path + NSArray *keyPathComponents = [keyPath componentsSeparatedByString:@"."]; + NSMutableSet *parentKeyPaths = [NSMutableSet set]; + for (NSUInteger index = 0; index < [keyPathComponents count] - 1; index++) { + [parentKeyPaths addObject:[[keyPathComponents subarrayWithRange:NSMakeRange(0, index + 1)] componentsJoinedByString:@"."]]; + } + for (NSString *parentKeyPath in parentKeyPaths) { + if ([setOfKeyPaths containsObject:parentKeyPath]) return NO; + } + return YES; + }]; +} + +// Precondition: Must be called from within the correct context +static NSManagedObject *RKRefetchManagedObjectInContext(NSManagedObject *managedObject, NSManagedObjectContext *managedObjectContext) +{ + NSManagedObjectID *managedObjectID = [managedObject objectID]; + if ([managedObjectID isTemporaryID]) { + RKLogWarning(@"Unable to refetch managed object %@: the object has a temporary managed object ID.", managedObject); + return managedObject; + } + NSError *error = nil; + NSManagedObject *refetchedObject = [managedObjectContext existingObjectWithID:managedObjectID error:&error]; + if (! refetchedObject) { + RKLogWarning(@"Failed to refetch managed object with ID %@: %@", managedObjectID, error); + } + return refetchedObject; +} + +static id RKRefetchedValueInManagedObjectContext(id value, NSManagedObjectContext *managedObjectContext) +{ + if (! value) { + return value; + } else if ([value isKindOfClass:[NSArray class]]) { + NSMutableArray *newValue = [[NSMutableArray alloc] initWithCapacity:[value count]]; + for (__strong id object in value) { + if ([object isKindOfClass:[NSManagedObject class]]) object = RKRefetchManagedObjectInContext(object, managedObjectContext); + if (object) [newValue addObject:object]; + } + return newValue; + } else if ([value isKindOfClass:[NSSet class]]) { + NSMutableSet *newValue = [[NSMutableSet alloc] initWithCapacity:[value count]]; + for (__strong id object in value) { + if ([object isKindOfClass:[NSManagedObject class]]) object = RKRefetchManagedObjectInContext(object, managedObjectContext); + if (object) [newValue addObject:object]; + } + return newValue; + } else if ([value isKindOfClass:[NSOrderedSet class]]) { + NSMutableOrderedSet *newValue = [NSMutableOrderedSet orderedSet]; + [(NSOrderedSet *)value enumerateObjectsUsingBlock:^(id object, NSUInteger index, BOOL *stop) { + if ([object isKindOfClass:[NSManagedObject class]]) object = RKRefetchManagedObjectInContext(object, managedObjectContext); + if (object) [newValue setObject:object atIndex:index]; + }]; + return newValue; + } else if ([value isKindOfClass:[NSManagedObject class]]) { + return RKRefetchManagedObjectInContext(value, managedObjectContext); + } + + return value; +} + +/** + This is an NSProxy object that stands in for the mapping result and provides support for refetching the results on demand. This enables us to defer the refetching until someone accesses the results directly. For managed object request operations that do not use the mapping result (such as those used in conjunction with a NSFetchedResultsController), the refetching will be skipped entirely. + */ +@interface RKRefetchingMappingResult : NSProxy + +- (instancetype)initWithMappingResult:(RKMappingResult *)mappingResult + managedObjectContext:(NSManagedObjectContext *)managedObjectContext + mappingInfo:(NSDictionary *)mappingInfo; +@end + +@interface RKRefetchingMappingResult () +@property (nonatomic, strong) RKMappingResult *mappingResult; +@property (nonatomic, strong) NSManagedObjectContext *managedObjectContext; +@property (nonatomic, strong) NSDictionary *mappingInfo; +@property (nonatomic, assign) BOOL refetched; +@end + +@implementation RKRefetchingMappingResult + ++ (NSString *)description +{ + return [[super description] stringByAppendingString:@"_RKRefetchingMappingResult"]; +} + +/** + Add explicit ordering of deallocations to fight `cxx_destruct` crashes + */ +- (void)dealloc +{ + _mappingResult = nil; + _mappingInfo = nil; + _managedObjectContext = nil; +} + +- (instancetype)initWithMappingResult:(RKMappingResult *)mappingResult + managedObjectContext:(NSManagedObjectContext *)managedObjectContext + mappingInfo:(NSDictionary *)mappingInfo; +{ + self.mappingResult = mappingResult; + self.managedObjectContext = managedObjectContext; + self.mappingInfo = mappingInfo; + return self; +} + +- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector +{ + return [self.mappingResult methodSignatureForSelector:selector]; +} + +- (void)forwardInvocation:(NSInvocation *)invocation +{ + if (! self.refetched) { + self.mappingResult = [self refetchedMappingResult]; + self.refetched = YES; + } + [invocation invokeWithTarget:self.mappingResult]; +} + +- (NSString *)description +{ + return [self.mappingResult description]; +} + +- (NSUInteger)count +{ + return [self.mappingResult count]; +} + +- (RKMappingResult *)refetchedMappingResult +{ + NSAssert(!self.refetched, @"Mapping result should only be refetched once"); + if (! [self.mappingResult count]) return self.mappingResult; + + NSMutableDictionary *newDictionary = [self.mappingResult.dictionary mutableCopy]; + [self.managedObjectContext performBlockAndWait:^{ + NSArray *entityMappingEvents = [RKEntityMappingEvent entityMappingEventsForMappingInfo:self.mappingInfo]; + NSSet *rootKeys = [NSSet setWithArray:[entityMappingEvents valueForKey:@"rootKey"]]; + for (id rootKey in rootKeys) { + NSArray *eventsForRootKey = [entityMappingEvents filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"rootKey = %@", rootKey]]; + NSSet *keyPaths = [NSSet setWithArray:[eventsForRootKey valueForKey:@"keyPath"]]; + // If keyPaths contains null, then the root object is a managed object and we only need to refetch it + NSSet *nonNestedKeyPaths = ([keyPaths containsObject:[NSNull null]]) ? [NSSet setWithObject:[NSNull null]] : RKSetByRemovingSubkeypathsFromSet(keyPaths); + + NSDictionary *mappingResultsAtRootKey = newDictionary[rootKey]; + for (NSString *keyPath in nonNestedKeyPaths) { + id value = nil; + if ([keyPath isEqual:[NSNull null]]) { + value = RKRefetchedValueInManagedObjectContext(mappingResultsAtRootKey, self.managedObjectContext); + if (value) newDictionary[rootKey] = value; + } else { + NSMutableArray *keyPathComponents = [[keyPath componentsSeparatedByString:@"."] mutableCopy]; + NSString *destinationKey = [keyPathComponents lastObject]; + [keyPathComponents removeLastObject]; + id sourceObject = [keyPathComponents count] ? [mappingResultsAtRootKey valueForKeyPath:[keyPathComponents componentsJoinedByString:@"."]] : mappingResultsAtRootKey; + if (RKObjectIsCollection(sourceObject)) { + // This is a to-many relationship, we want to refetch each item at the keyPath + for (id nestedObject in sourceObject) { + // NOTE: If this collection was mapped with a dynamic mapping then each instance may not respond to the key + if ([nestedObject respondsToSelector:NSSelectorFromString(destinationKey)]) { + NSManagedObject *managedObject = [nestedObject valueForKey:destinationKey]; + [nestedObject setValue:RKRefetchedValueInManagedObjectContext(managedObject, self.managedObjectContext) forKey:destinationKey]; + } + } + } else { + // This is a singular relationship. We want to refetch the object and set it directly. + id valueToRefetch = [sourceObject valueForKey:destinationKey]; + [sourceObject setValue:RKRefetchedValueInManagedObjectContext(valueToRefetch, self.managedObjectContext) forKey:destinationKey]; + } + } + } + } + }]; + + return [[RKMappingResult alloc] initWithDictionary:newDictionary]; +} + +@end + +NSArray *RKArrayOfFetchRequestFromBlocksWithURL(NSArray *fetchRequestBlocks, NSURL *URL) +{ + NSMutableArray *fetchRequests = [NSMutableArray array]; + NSFetchRequest *fetchRequest = nil; + for (RKFetchRequestBlock block in [fetchRequestBlocks reverseObjectEnumerator]) { + fetchRequest = block(URL); + if (fetchRequest) [fetchRequests addObject:fetchRequest]; + } + return fetchRequests; +} + +static NSSet *RKFlattenCollectionToSet(id collection) +{ + NSMutableSet *mutableSet = [NSMutableSet set]; + if ([collection conformsToProtocol:@protocol(NSFastEnumeration)]) { + for (id nestedObject in collection) { + if ([nestedObject conformsToProtocol:@protocol(NSFastEnumeration)]) { + if ([nestedObject isKindOfClass:[NSArray class]]) { + [mutableSet unionSet:RKFlattenCollectionToSet([NSSet setWithArray:nestedObject])]; + } else if ([nestedObject isKindOfClass:[NSSet class]]) { + [mutableSet unionSet:RKFlattenCollectionToSet(nestedObject)]; + } else if ([nestedObject isKindOfClass:[NSOrderedSet class]]) { + [mutableSet unionSet:RKFlattenCollectionToSet([(NSOrderedSet *)nestedObject set])]; + } + } else { + [mutableSet addObject:nestedObject]; + } + } + } else if (collection) { + [mutableSet addObject:collection]; + } + + return mutableSet; +} + +static NSURL *RKRelativeURLFromURLAndResponseDescriptors(NSURL *URL, NSArray *responseDescriptors) +{ + NSCParameterAssert(URL); + NSCParameterAssert(responseDescriptors); + NSArray *baseURLs = [responseDescriptors valueForKeyPath:@"@distinctUnionOfObjects.baseURL"]; + if ([baseURLs count] == 1) { + NSURL *baseURL = baseURLs[0]; + NSString *pathAndQueryString = RKPathAndQueryStringFromURLRelativeToURL(URL, baseURL); + URL = [NSURL URLWithString:pathAndQueryString relativeToURL:baseURL]; + } + + return URL; +} + +static void RKGatherManagedObjectsFromObjectWithRelationshipMapping(id object, RKRelationshipMapping *relationshipMapping, NSMutableSet *managedObjects) +{ + NSSet *relationshipValue = RKFlattenCollectionToSet([object valueForKeyPath:relationshipMapping.destinationKeyPath]); + for (id relatedObject in relationshipValue) { + if ([managedObjects containsObject:relatedObject]) continue; + if ([relatedObject isKindOfClass:[NSManagedObject class]]) [managedObjects addObject:relatedObject]; + + if ([relationshipMapping.mapping isKindOfClass:[RKObjectMapping class]]) { + for (RKRelationshipMapping *childRelationshipMapping in [(RKObjectMapping *)relationshipMapping.mapping relationshipMappings]) { + RKGatherManagedObjectsFromObjectWithRelationshipMapping(relatedObject, childRelationshipMapping, managedObjects); + } + } else if ([relationshipMapping.mapping isKindOfClass:[RKDynamicMapping class]]) { + for (RKObjectMapping *objectMapping in [(RKDynamicMapping *)relationshipMapping.mapping objectMappings]) { + @try { + for (RKRelationshipMapping *childRelationshipMapping in objectMapping.relationshipMappings) { + RKGatherManagedObjectsFromObjectWithRelationshipMapping(relatedObject, childRelationshipMapping, managedObjects); + } + } + @catch (NSException *exception) { + continue; + } + } + } + } +} + +static NSSet *RKManagedObjectsFromObjectWithMappingInfo(id object, RKMappingInfo *mappingInfo) +{ + NSMutableSet *managedObjects = [NSMutableSet set]; + + if ([mappingInfo.objectMapping isKindOfClass:[RKEntityMapping class]]) { + [managedObjects unionSet:RKFlattenCollectionToSet(object)]; + } + + if ([[mappingInfo propertyMappings] count] == 0) { + // This object was matched, but no changes were made. Gather all related objects + for (RKRelationshipMapping *relationshipMapping in [mappingInfo.objectMapping relationshipMappings]) { + RKGatherManagedObjectsFromObjectWithRelationshipMapping(object, relationshipMapping, managedObjects); + } + } else { + for (NSString *destinationKeyPath in mappingInfo.relationshipMappingInfo) { + id relationshipValue = nil; + // Objects in collection may have different types, so destination keypath may be not applicable to each of them + if([object conformsToProtocol:@protocol(NSFastEnumeration)]) { + NSMutableSet* results = [NSMutableSet set]; + for (id item in object) { + @try { + id value = [item valueForKeyPath:destinationKeyPath]; + [results addObject:value]; + } @catch(NSException*) { + continue; + } + } + + relationshipValue = results; + } else { + relationshipValue = [object valueForKeyPath:destinationKeyPath]; + } + + NSArray *mappingInfos = (mappingInfo.relationshipMappingInfo)[destinationKeyPath]; + for (RKMappingInfo *relationshipMappingInfo in mappingInfos) { + NSUInteger index = [mappingInfos indexOfObject:relationshipMappingInfo]; + id mappedObjectAtIndex = ([relationshipValue respondsToSelector:@selector(objectAtIndex:)]) ? relationshipValue[index] : relationshipValue; + [managedObjects unionSet:RKFlattenCollectionToSet(RKManagedObjectsFromObjectWithMappingInfo(mappedObjectAtIndex, relationshipMappingInfo))]; + } + } + } + + return ([managedObjects count]) ? managedObjects : nil; +} + +static NSSet *RKManagedObjectsFromMappingResultWithMappingInfo(RKMappingResult *mappingResult, NSDictionary *mappingInfo) +{ + NSMutableSet *managedObjectsInMappingResult = nil; + NSDictionary *mappingResultDictionary = [mappingResult dictionary]; + + for (id rootKey in mappingInfo) { + NSArray *mappingInfoArray = mappingInfo[rootKey]; + id objectsAtRoot = mappingResultDictionary[rootKey]; + for (RKMappingInfo *mappingInfo in mappingInfoArray) { + NSUInteger index = [mappingInfoArray indexOfObject:mappingInfo]; + id mappedObjectAtIndex = ([objectsAtRoot respondsToSelector:@selector(objectAtIndex:)]) ? objectsAtRoot[index] : objectsAtRoot; + + NSSet *managedObjects = RKManagedObjectsFromObjectWithMappingInfo(mappedObjectAtIndex, mappingInfo); + if (managedObjects) { + if (! managedObjectsInMappingResult) managedObjectsInMappingResult = [NSMutableSet set]; + [managedObjectsInMappingResult unionSet:managedObjects]; + } + } + }; + + return managedObjectsInMappingResult; +} + +// Defined in RKObjectManager.h +BOOL RKDoesArrayOfResponseDescriptorsContainOnlyEntityMappings(NSArray *responseDescriptors); + +@interface RKObjectRequestOperation () +@property (nonatomic, strong, readwrite) NSError *error; +@property (nonatomic, strong, readwrite) RKMappingResult *mappingResult; +@end + +@interface RKManagedObjectRequestOperation () +// Core Data specific +@property (nonatomic, strong) NSManagedObjectContext *privateContext; +@property (nonatomic, copy) NSManagedObjectID *targetObjectID; +@property (nonatomic, strong) RKManagedObjectResponseMapperOperation *responseMapperOperation; +@property (nonatomic, copy) id (^willMapDeserializedResponseBlock)(id deserializedResponseBody); +@property (nonatomic, strong) NSDictionary *mappingInfo; +@property (nonatomic, strong) NSCachedURLResponse *cachedResponse; +@property (nonatomic, readonly) BOOL canSkipMapping; +@property (nonatomic, assign) BOOL hasMemoizedCanSkipMapping; +@property (nonatomic, copy) void (^willSaveMappingContextBlock)(NSManagedObjectContext *mappingContext); +@end + +@implementation RKManagedObjectRequestOperation + +@dynamic willMapDeserializedResponseBlock; +@synthesize canSkipMapping = _canSkipMapping; + +// Designated initializer +- (instancetype)initWithHTTPRequestOperation:(RKHTTPRequestOperation *)requestOperation responseDescriptors:(NSArray *)responseDescriptors +{ + self = [super initWithHTTPRequestOperation:requestOperation responseDescriptors:responseDescriptors]; + if (self) { + self.savesToPersistentStore = YES; + self.deletesOrphanedObjects = YES; + self.cachedResponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:requestOperation.request]; + } + return self; +} + +/** + NOTE: This dealloc implementation attempts to avoid crashes coming from Core Data due to the ordering of deallocations under ARC. If the MOC is deallocated before its managed objects, it can trigger a crash. We dispose of the mapping result and reset the private context to avoid this situation. The crash manifests itself in `cxx_destruct` + [sbw - 2/25/2013] + */ +- (void)dealloc +{ + _mappingResult = nil; + _responseMapperOperation = nil; + _privateContext = nil; +} + +- (void)setTargetObject:(id)targetObject +{ + [super setTargetObject:targetObject]; + + if ([targetObject isKindOfClass:[NSManagedObject class]]) { + if ([[targetObject objectID] isTemporaryID]) { + [[targetObject managedObjectContext] performBlockAndWait:^{ + NSError *error = nil; + BOOL success = [[targetObject managedObjectContext] obtainPermanentIDsForObjects:@[ targetObject ] error:&error]; + if (! success) RKLogWarning(@"Failed to obtain permanent objectID for targetObject: %@ (%ld)", [error localizedDescription], (long) error.code); + }]; + } + self.targetObjectID = [targetObject objectID]; + } else { + self.targetObjectID = nil; + } +} + +- (void)setManagedObjectContext:(NSManagedObjectContext *)managedObjectContext +{ + _managedObjectContext = managedObjectContext; + + if (managedObjectContext) { + [managedObjectContext performBlockAndWait:^{ + if ([managedObjectContext hasChanges]) { + if ([managedObjectContext.insertedObjects count] && [self.managedObjectCache respondsToSelector:@selector(didCreateObject:)]) { + for (NSManagedObject *managedObject in managedObjectContext.insertedObjects) { + [self.managedObjectCache didCreateObject:managedObject]; + } + } + + if ([managedObjectContext.updatedObjects count] && [self.managedObjectCache respondsToSelector:@selector(didFetchObject:)]) { + for (NSManagedObject *managedObject in managedObjectContext.updatedObjects) { + [self.managedObjectCache didFetchObject:managedObject]; + } + } + + if ([managedObjectContext.deletedObjects count] && [self.managedObjectCache respondsToSelector:@selector(didDeleteObject:)]) { + for (NSManagedObject *managedObject in managedObjectContext.deletedObjects) { + [self.managedObjectCache didDeleteObject:managedObject]; + } + } + } + }]; + + // Create a private context + NSManagedObjectContext *privateContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]; + [privateContext setParentContext:managedObjectContext]; + [privateContext setMergePolicy:NSMergeByPropertyStoreTrumpMergePolicy]; + + self.privateContext = privateContext; + } else { + self.privateContext = nil; + } +} + +#pragma mark - RKObjectRequestOperation Overrides + +- (void)cancel +{ + [super cancel]; + [self.responseMapperOperation cancel]; +} + +// RKResponseHasBeenMappedCacheUserInfoKey is stored by RKObjectRequestOperation +- (BOOL)canSkipMapping +{ + BOOL (^shouldSkipMapping)(void) = ^{ + // Is the request cacheable + if (!self.cachedResponse) return NO; + if (!self.managedObjectCache) return NO; + NSURLRequest *request = self.HTTPRequestOperation.request; + if (! [[request HTTPMethod] isEqualToString:@"GET"] && ! [[request HTTPMethod] isEqualToString:@"HEAD"]) return NO; + NSHTTPURLResponse *response = (NSHTTPURLResponse *)self.HTTPRequestOperation.response; + if (! [RKCacheableStatusCodes() containsIndex:response.statusCode]) return NO; + + // Check if all the response descriptors are backed by Core Data + NSMutableArray *matchingResponseDescriptors = [NSMutableArray array]; + for (RKResponseDescriptor *responseDescriptor in self.responseDescriptors) { + if ([responseDescriptor matchesResponse:response]) [matchingResponseDescriptors addObject:responseDescriptor]; + } + if (! RKDoesArrayOfResponseDescriptorsContainOnlyEntityMappings(matchingResponseDescriptors)) return NO; + + // Check for a change in the Etag + NSString *cachedEtag = [(NSHTTPURLResponse *)[self.cachedResponse response] allHeaderFields][@"ETag"]; + NSString *responseEtag = [response allHeaderFields][@"ETag"]; + if (!(cachedEtag && responseEtag && [cachedEtag isEqualToString:responseEtag])) return NO; + + // Response data has changed + NSData *responseData = self.HTTPRequestOperation.responseData; + if (! [responseData isEqualToData:[self.cachedResponse data]]) return NO; + + // Check that we have mapped this response previously + NSCachedURLResponse *cachedResponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:request]; + return [(cachedResponse.userInfo)[RKResponseHasBeenMappedCacheUserInfoKey] boolValue]; + }; + + if (! self.hasMemoizedCanSkipMapping) { + _canSkipMapping = shouldSkipMapping(); + self.hasMemoizedCanSkipMapping = YES; + } + return _canSkipMapping; +} + +- (void)performMappingOnResponseWithCompletionBlock:(void(^)(RKMappingResult *mappingResult, NSError *error))completionBlock +{ + NSArray *fetchRequests = [self fetchRequestsMatchingResponseURL]; + if ([fetchRequests count] && [self canSkipMapping]) { + RKLogDebug(@"Managed object mapping requested for cached response which was previously mapped: skipping..."); + NSMutableArray *managedObjects = [NSMutableArray array]; + [self.privateContext performBlockAndWait:^{ + NSError *error = nil; + for (NSFetchRequest *fetchRequest in fetchRequests) { + NSArray *fetchedObjects = [self.privateContext executeFetchRequest:fetchRequest error:&error]; + if (fetchedObjects) { + [managedObjects addObjectsFromArray:fetchedObjects]; + } else { + RKLogError(@"Failed to execute fetch request %@: %@", fetchRequest, error); + } + } + }]; + RKMappingResult *mappingResult = [[RKMappingResult alloc] initWithDictionary:@{ [NSNull null]: managedObjects }]; + completionBlock(mappingResult, nil); + return; + } + + self.responseMapperOperation = [[RKManagedObjectResponseMapperOperation alloc] initWithRequest:self.HTTPRequestOperation.request + response:self.HTTPRequestOperation.response + data:self.HTTPRequestOperation.responseData + responseDescriptors:self.responseDescriptors]; + self.responseMapperOperation.mapperDelegate = self; + self.responseMapperOperation.mappingMetadata = self.mappingMetadata; + self.responseMapperOperation.targetObject = self.targetObject; + self.responseMapperOperation.targetObjectID = self.targetObjectID; + self.responseMapperOperation.managedObjectContext = self.privateContext; + self.responseMapperOperation.managedObjectCache = self.managedObjectCache; + [self.responseMapperOperation setWillMapDeserializedResponseBlock:self.willMapDeserializedResponseBlock]; + [self.responseMapperOperation setQueuePriority:[self queuePriority]]; + __weak __typeof(self)weakSelf = self; + [self.responseMapperOperation setDidFinishMappingBlock:^(RKMappingResult *mappingResult, NSError *responseMappingError) { + if ([weakSelf isCancelled]) return completionBlock(mappingResult, responseMappingError); + + BOOL success; + NSError *error = nil; + + // Handle any cleanup + if (weakSelf.targetObjectID + && NSLocationInRange(weakSelf.HTTPRequestOperation.response.statusCode, RKStatusCodeRangeForClass(RKStatusCodeClassSuccessful)) + && [[[weakSelf.HTTPRequestOperation.request HTTPMethod] uppercaseString] isEqualToString:@"DELETE"]) { + success = [weakSelf deleteTargetObject:&error]; + if (! success || [weakSelf isCancelled]) { + return completionBlock(nil, error); + } + } + + if (!responseMappingError) { + success = [weakSelf deleteLocalObjectsMissingFromMappingResult:mappingResult error:&error]; + if (! success || [weakSelf isCancelled]) { + return completionBlock(nil, error); + } + + // Persist our mapped objects + success = [weakSelf obtainPermanentObjectIDsForInsertedObjects:&error]; + if (! success || [weakSelf isCancelled]) { + return completionBlock(nil, error); + } + + success = [weakSelf saveContext:&error]; + if (! success || [weakSelf isCancelled]) { + return completionBlock(nil, error); + } + } + + // Refetch all managed objects nested at key paths within the results dictionary before returning + if (mappingResult) { + RKRefetchingMappingResult *refetchingMappingResult = [[RKRefetchingMappingResult alloc] initWithMappingResult:mappingResult + managedObjectContext:weakSelf.managedObjectContext + mappingInfo:weakSelf.mappingInfo]; + return completionBlock((RKMappingResult *)refetchingMappingResult, nil); + } + completionBlock(nil, responseMappingError); + }]; + [[RKObjectRequestOperation responseMappingQueue] addOperation:self.responseMapperOperation]; +} + +- (BOOL)deleteTargetObject:(NSError **)error +{ + __block BOOL _blockSuccess = YES; + + if (self.targetObjectID) { + // 2xx/404/410 DELETE request, proceed with deletion from the MOC + __block NSError *_blockError = nil; + [self.privateContext performBlockAndWait:^{ + NSManagedObject *backgroundThreadObject = [self.privateContext existingObjectWithID:self.targetObjectID error:&_blockError]; + if (backgroundThreadObject) { + RKLogInfo(@"Deleting local object %@ due to `DELETE` request", backgroundThreadObject); + [self.privateContext deleteObject:backgroundThreadObject]; + } else { + RKLogWarning(@"Unable to delete object sent with `DELETE` request: Failed to retrieve object with objectID %@", self.targetObjectID); + RKLogCoreDataError(_blockError); + _blockSuccess = NO; + *error = _blockError; + } + }]; + } + + return _blockSuccess; +} + +- (NSSet *)localObjectsFromFetchRequests:(NSArray *)fetchRequests matchingRequestURL:(NSError **)error +{ + NSMutableSet *localObjects = [NSMutableSet set]; + __block NSError *_blockError; + __block NSArray *_blockObjects; + + for (NSFetchRequest *fetchRequest in fetchRequests) { + [self.privateContext performBlockAndWait:^{ + _blockObjects = [self.privateContext executeFetchRequest:fetchRequest error:&_blockError]; + }]; + + if (_blockObjects == nil) { + if (error) *error = _blockError; + return nil; + } + RKLogTrace(@"Fetched local objects matching URL with fetch request '%@': %@", fetchRequest, _blockObjects); + [localObjects addObjectsFromArray:_blockObjects]; + + } + + return localObjects; +} + +- (NSArray *)fetchRequestsMatchingResponseURL +{ + // Pass the fetch request blocks a relative `NSURL` object if possible + NSMutableArray *fetchRequests = [NSMutableArray array]; + NSURL *URL = RKRelativeURLFromURLAndResponseDescriptors(self.HTTPRequestOperation.response.URL, self.responseDescriptors); + for (RKFetchRequestBlock fetchRequestBlock in [self.fetchRequestBlocks reverseObjectEnumerator]) { + NSFetchRequest *fetchRequest = fetchRequestBlock(URL); + if (fetchRequest) { + // Workaround for iOS 5 -- The log statement crashes if the entity is not assigned before logging + [fetchRequest setEntity:[[[self.privateContext persistentStoreCoordinator] managedObjectModel] entitiesByName][[fetchRequest entityName]]]; + RKLogDebug(@"Found fetch request matching URL '%@': %@", URL, fetchRequest); + [fetchRequests addObject:fetchRequest]; + } + } + return fetchRequests; +} + +- (BOOL)deleteLocalObjectsMissingFromMappingResult:(RKMappingResult *)mappingResult error:(NSError **)error +{ + if (! self.deletesOrphanedObjects) { + RKLogDebug(@"Skipping deletion of orphaned objects: disabled as deletesOrphanedObjects=NO"); + return YES; + } + + if (! [[self.HTTPRequestOperation.request.HTTPMethod uppercaseString] isEqualToString:@"GET"]) { + RKLogDebug(@"Skipping deletion of orphaned objects: only performed for GET requests."); + return YES; + } + + if ([self canSkipMapping]) { + RKLogDebug(@"Skipping deletion of orphaned objects: 304 (Not Modified) status code encountered"); + return YES; + } + + // Determine if there are any fetch request blocks to use for orphaned object cleanup + NSArray *fetchRequests = [self fetchRequestsMatchingResponseURL]; + if (! [fetchRequests count]) return YES; + + // Proceed with cleanup + __block NSSet *managedObjectsInMappingResult; + [self.privateContext performBlockAndWait:^{ + managedObjectsInMappingResult = RKManagedObjectsFromMappingResultWithMappingInfo(mappingResult, self.mappingInfo) ?: [NSSet set]; + }]; + NSSet *localObjects = [self localObjectsFromFetchRequests:fetchRequests matchingRequestURL:error]; + if (! localObjects) { + RKLogError(@"Failed when attempting to fetch local candidate objects for orphan cleanup: %@", error ? *error : nil); + return NO; + } + RKLogDebug(@"Checking mappings result of %ld objects for %ld potentially orphaned local objects...", (long) [managedObjectsInMappingResult count], (long) [localObjects count]); + + NSMutableSet *orphanedObjects = [localObjects mutableCopy]; + [orphanedObjects minusSet:managedObjectsInMappingResult]; + RKLogDebug(@"Deleting %lu orphaned objects found in local database, but missing from mapping result", (unsigned long) [orphanedObjects count]); + + if ([orphanedObjects count]) { + [self.privateContext performBlockAndWait:^{ + for (NSManagedObject *orphanedObject in orphanedObjects) { + [self.privateContext deleteObject:orphanedObject]; + } + }]; + } + + return YES; +} + +/** + NOTE: This is more or less a direct port of the functionality provided by `[NSManagedObjectContext saveToPersistentStore:]` in the `RKAdditions` category. We have duplicated the logic here to add in support for checking if the operation has been cancelled since we began cascading up the MOC chain. Because each `performBlockAndWait:` invocation essentially jumps threads and is subject to the availability of the context, it is very possible for the operation to be cancelled during this part of the operation's lifecycle. + */ +- (BOOL)saveContextToPersistentStore:(NSManagedObjectContext *)contextToSave error:(NSError **)error +{ + __block NSError *localError = nil; + while (contextToSave) { + __block BOOL success; + [contextToSave performBlockAndWait:^{ + if (! [self isCancelled]) { + success = [contextToSave save:&localError]; + if (! success && localError == nil) RKLogWarning(@"Saving of managed object context failed, but a `nil` value for the `error` argument was returned. This typically indicates an invalid implementation of a key-value validation method exists within your model. This violation of the API contract may result in the save operation being mis-interpretted by callers that rely on the availability of the error."); + } else { + // We have been cancelled while the save is in progress -- bail + success = NO; + } + }]; + + if (! success) { + if (error) *error = localError; + return NO; + } + + if (! contextToSave.parentContext && contextToSave.persistentStoreCoordinator == nil) { + RKLogWarning(@"Reached the end of the chain of nested managed object contexts without encountering a persistent store coordinator. Objects are not fully persisted."); + return NO; + } + contextToSave = contextToSave.parentContext; + } + + return YES; +} + +- (BOOL)saveContext:(NSManagedObjectContext *)context error:(NSError **)error +{ + __block BOOL success = YES; + __block NSError *localError = nil; + if (self.savesToPersistentStore) { + success = [self saveContextToPersistentStore:context error:&localError]; + } else { + [context performBlockAndWait:^{ + success = ([self isCancelled]) ? NO : [context save:&localError]; + }]; + } + if (success) { + if ([self.targetObject isKindOfClass:[NSManagedObject class]]) { + [self.managedObjectContext performBlock:^{ + RKLogDebug(@"Refreshing mapped target object %@ in context %@", self.targetObject, self.managedObjectContext); + if (! [self isCancelled]) [self.managedObjectContext refreshObject:self.targetObject mergeChanges:YES]; + }]; + } + } else { + if (error) *error = localError; + RKLogError(@"Failed saving managed object context %@ %@: %@", (self.savesToPersistentStore ? @"to the persistent store" : @""), context, localError); + RKLogCoreDataError(localError); + } + + return success; +} + +- (BOOL)saveContext:(NSError **)error +{ + if (self.willSaveMappingContextBlock) { + self.mappingResult = _responseMapperOperation.mappingResult; + [self.privateContext performBlockAndWait:^{ + self.willSaveMappingContextBlock(self.privateContext); + }]; + } + + __block BOOL hasChanges; + [self.privateContext performBlockAndWait:^{ + hasChanges = [self.privateContext hasChanges]; + }]; + if (hasChanges) { + return [self saveContext:self.privateContext error:error]; + } else if ([self.targetObject isKindOfClass:[NSManagedObject class]]) { + NSManagedObjectContext *context = [(NSManagedObject *)self.targetObject managedObjectContext]; + __block BOOL isNew = NO; + [context performBlockAndWait:^{ + isNew = [(NSManagedObject *)self.targetObject isNew]; + }]; + // Object was like POST'd in an unsaved state and we wish to persist + if (isNew) [self saveContext:context error:error]; + } + + return YES; +} + +- (BOOL)obtainPermanentObjectIDsForInsertedObjects:(NSError **)error +{ + __block BOOL _blockSuccess = YES; + __block NSError *localError = nil; + [self.privateContext performBlockAndWait:^{ + NSArray *insertedObjects = [[self.privateContext insertedObjects] allObjects]; + RKLogDebug(@"Obtaining permanent ID's for %ld managed objects", (unsigned long) [insertedObjects count]); + _blockSuccess = [self.privateContext obtainPermanentIDsForObjects:insertedObjects error:&localError]; + }]; + if (!_blockSuccess && error) *error = localError; + + return _blockSuccess;; +} + +- (void)mapperDidFinishMapping:(RKMapperOperation *)mapper +{ + self.mappingInfo = mapper.mappingInfo; +} + +- (void)willFinish +{ + NSMutableIndexSet *deleteableStatusCodes = [NSMutableIndexSet indexSet]; + [deleteableStatusCodes addIndex:404]; // Not Found + [deleteableStatusCodes addIndex:410]; // Gone + if (self.error && self.targetObjectID + && [[[self.HTTPRequestOperation.request HTTPMethod] uppercaseString] isEqualToString:@"DELETE"] + && [deleteableStatusCodes containsIndex:self.HTTPRequestOperation.response.statusCode]) { + NSError *error = nil; + if (! [self deleteTargetObject:&error]) { + RKLogWarning(@"Secondary error encountered while attempting to delete target object in response to 404 (Not Found) or 410 (Gone) status code: %@", error); + self.error = error; + } else { + if (! [self saveContext:&error]) { + + } else { + // All good, clear any errors + self.error = nil; + } + } + } +} + +#pragma mark - NSCopying + +- (id)copyWithZone:(NSZone *)zone { + RKManagedObjectRequestOperation *operation = (RKManagedObjectRequestOperation *)[super copyWithZone:zone]; + operation.managedObjectContext = self.managedObjectContext; + operation.managedObjectCache = self.managedObjectCache; + operation.fetchRequestBlocks = self.fetchRequestBlocks; + operation.deletesOrphanedObjects = self.deletesOrphanedObjects; + operation.savesToPersistentStore = self.savesToPersistentStore; + + return operation; +} + +@end + +#endif +#endif diff --git a/Pods/RestKit/Code/Network/RKObjectManager.h b/Pods/RestKit/Code/Network/RKObjectManager.h new file mode 100644 index 0000000..7b107b6 --- /dev/null +++ b/Pods/RestKit/Code/Network/RKObjectManager.h @@ -0,0 +1,893 @@ +// +// RKObjectManager.h +// RestKit +// +// Created by Jeremy Ellison on 8/14/09. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKRouter.h" +#import "RKPaginator.h" +#import "RKMacros.h" + +#import + +#ifdef _COREDATADEFINES_H +# if __has_include("RKCoreData.h") +# define RKCoreDataIncluded +# endif +#endif + +@protocol RKSerialization; +@class RKManagedObjectStore, RKObjectRequestOperation, RKManagedObjectRequestOperation, +RKMappingResult, RKRequestDescriptor, RKResponseDescriptor; + +/** + The `RKObjectManager` class provides a centralized interface for performing object mapping based HTTP request and response operations. It encapsulates common configuration such as request/response descriptors and routing, provides for the creation of `NSURLRequest` and `RKObjectRequestOperation` objects, and one-line methods to enqueue object request operations for the basic HTTP request methods (GET, POST, PUT, DELETE, etc). + + ## Object Request Operations + + Object request operations model the lifecycle of an object mapped HTTP request from start to finish. They are initialized with a fully configured `NSURLRequest` object and a set of `RKResponseDescriptor` objects that specify how an HTTP response is to be mapped into local domain objects. Object request operations may be constructed as standalone objects, but are often constructed through an `RKObjectManager` object. The object request operation encapsulates the functionality of two underlying operations that perform the bulk of the work. The HTTP request and response loading is handled by an `RKHTTPRequestOperation`, which is responsible for the HTTP transport details. Once a response has been successfully loaded, the object request operation starts an `RKResponseMapperOperation` that is responsible for handling the mapping of the response body. When working with Core Data, the `RKManagedObjectRequestOperation` class is used. The object manager encapsulates the Core Data configuration details and provides an interface that will return the appropriate object request operation for a request through the `appropriateObjectRequestOperationWithObject:method:path:parameters:` method. + + ## Base URL, Relative Paths and Path Patterns + + Each object manager is configured with a base URL that defines the URL that all request sent through the manager will be relative to. The base URL is configured directly through the `managerWithBaseURL:` method or is inherited from an AFNetworking `AFHTTPClient` object if the manager is initialized via the `initWithHTTPClient:` method. The base URL can point directly at the root of a URL or may include a path. + + Many of the methods of the object manager accept a path argument, either directly or in the form of a path pattern. Whenever a path is provided to the object manager directly, as part of a request or response descriptor (see "Request and Response Descriptors"), or via a route (see the "Routing" section), the path is used to construct an `NSURL` object with `[NSURL URLWithString:relativeToURL:]`. The rules for the evaluation of a relative URL can at times be surprising and many configuration errors result from incorrectly configuring the `baseURL` and relative paths thereof. For reference, here are some examples borrowed from the AFNetworking documentation detailing how base URL's and relative paths interact: + + NSURL *baseURL = [NSURL URLWithString:@"http://example.com/v1/"]; + [NSURL URLWithString:@"foo" relativeToURL:baseURL]; // http://example.com/v1/foo + [NSURL URLWithString:@"foo?bar=baz" relativeToURL:baseURL]; // http://example.com/v1/foo?bar=baz + [NSURL URLWithString:@"/foo" relativeToURL:baseURL]; // http://example.com/foo + [NSURL URLWithString:@"foo/" relativeToURL:baseURL]; // http://example.com/v1/foo + [NSURL URLWithString:@"/foo/" relativeToURL:baseURL]; // http://example.com/foo/ + [NSURL URLWithString:@"http://example2.com/" relativeToURL:baseURL]; // http://example2.com/ + + Keep these rules in mind when providing relative paths to the object manager. + + Path patterns are a common unit of abstraction in RestKit for describing the path portion of URL's. When working with API's, there is typically one or more dynamic portions of the URL that correspond to primary keys or other identifying resource attributes. For example, a blogging application may represent articles in a URL structure such as '/articles/1234' and comments about an article might appear at '/articles/1234/comments'. These path structures could be represented as the path patterns '/articles/:articleID' and '/articles/:articleID/comments', substituing the dynamic key ':articleID' in place of the primary key of in the path. These keys can be used to interpolate a path with an object's property values using key-value coding or be used to match a string. + + Path patterns appear throughout RestKit, but the most fundamental uses are for the dynamic generation of URL paths from objects and the matching of request and response URLs for mapping configuration. When generating a URL, a path pattern is interpolated with the value of an object. Consider this example: + + // Set object attributes + RKArticle *article = [RKArticle new]; + article.articleID = @12345; + + // Interpolate with the object + NSString *path = RKPathFromPatternWithObject(@"/articles/:articleID", article); + NSLog(@"The path is %@", path); // prints /articles/12345 + + This may at first glance appear to provide only a small syntactic improvement over using `[NSString stringWithFormat:]`, but it becomes more interesting once you consider that the dynamic key can include key path: + + RKCategory *category = [RKCategory new]; + comment.name = @"RestKit; + article.category = category; + + NSString *path = RKPathFromPatternWithObject(@"/categories/:comment.name/articles/:articleID/comments/", article); + NSLog(@"The path is %@", path); // prints /categories/RestKit/articles/12345 + + These path patterns can then be registered with the manager via an `RKRoute` object (discussed in detail below), enabling one to perform object request operations like so: + + RKObjectManager *manager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:@"http://restkit.org"]]; + [manager.router.routeSet addRoute:[RKRoute routeWithClass:[RKArticle class] pathPattern:@"/categories/:comment.name/articles/:articleID/comments/" method:RKRequestMethodGET]]; + + // Now GET our article object... sending a GET to '/categories/RestKit/articles/12345' + [manager getObject:article path:nil parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *result) { + NSLog(@"Loading mapping result: %@", result); + } failure:nil]; + + Once a path pattern has been registered via the routing system, the manager can automatically build full request URL's when given nothing but the object to be sent. + + The second use case of path patterns is in the matching of path into a dictionary of attributes. In this case, the path pattern is evaluatd against a string and used to construct an `NSDictionary` object containing the matched key paths, optionally including the values of a query string. This functionality is provided via the `RKPathMatcher` class and is discussed in detail in the accompanying documentation. + + ### Escaping Path Patterns + + Note that path patterns will by default interpret anything prefixed with a period that follows a dynamic path segment as a key path. This can cause an issue if you have a dynamic path segment that is followed by a file extension. For example, a path pattern of '/categories/:categoryID.json' would be erroneously interpretted as containing a dynamic path segment whose value is interpolated from the 'categoryID.json' key path. This key path evaluation behavior can be suppressed by escaping the period preceding the non-dynamic part of the pattern with two leading slashes, as in '/categories/:categoryID\\.json'. + + ## Request and Response Descriptors + + RestKit centralizes configuration for object mapping configurations into the object manager through `RKRequestDescriptor` and `RKResponseDescriptor` objects. A collection of each of these object types are maintained by the manager and used to initialize all `RKObjectRequestOperation` objects created by the manager. + + Request descriptors describe how `NSURLRequest` objects constructed by the manager will be built by specifying how the attributes and relationships for a given class will be object mapped to construct request parameters and what, if any, root key path the parameters will be nested under. Request descriptor objects can also be used with the `RKObjectParameterization` class to map an object into an `NSDictionary` representation that is suitable for use as the parameters of a request. + + Response descriptors describe how `NSHTTPURLResponse` objects loaded by object request operations sent by the manager are to be object mapped into local domain objects. Response descriptors are matched against a given response via URL path matching, parsed content key path matching, or both. The `RKMapping` object associated from a matched `RKResponseDescriptor` is given to an instance of `RKMapperOperation` with the parsed response body to perform object mapping on the response. + + To better illustrate these concepts, consider the following example for an imaginary Wiki client application: + + @interface RKWikiPage : NSObject + @property (nonatomic, copy) NSString *title; + @property (nonatomic, copy) NSString *body; + @end + + // Construct a request mapping for our class + RKObjectMapping *requestMapping = [RKObjectMapping requestMapping]; + [requestMapping addAttributeMappingsFromDictionary:@{ @"title": @"title", @"body": @"body" }]; + + // We wish to generate parameters of the format: + // @{ @"page": @{ @"title": @"An Example Page", @"body": @"Some example content" } } + RKRequestDescriptor *requestDescriptor = [RKRequestDescriptor requestDescriptorWithMapping:mapping + objectClass:[RKWikiPage class] + rootKeyPath:@"page"]; + + // Construct an object mapping for the response + // We are expecting JSON in the format: + // {"page": {"title": "", "body": "<body value>"} + RKObjectMapping *responseMapping = [RKObjectMapping mappingForClass:[RKWikiPage class]]; + [responseMapping addAttributeMappingsFromArray:@[ @"title", @"body" ]]; + + // Construct a response descriptor that matches any URL (the pathPattern is nil), when the response payload + // contains content nested under the `@"page"` key path, if the response status code is 200 (OK) + RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:responseMapping + pathPattern:nil + keyPath:@"page" + statusCodes:[NSIndexSet indexSetWithIndex:200]]; + + // Register our descriptors with a manager + RKObjectManager *manager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:@"http://restkit.org/"]]; + [manager addRequestDescriptor:requestDescriptor]; + [manager addResponseDescriptor:responseDescriptor]; + + // Work with the object + RKWikiPage *page = [RKWikiPage new]; + page.title = @"An Example Page"; + page.body = @"Some example content"; + + // POST the parameterized representation of the `page` object to `/posts` and map the response + [manager postObject:page path:@"/pages" parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *result) { + NSLog(@"We object mapped the response with the following result: %@", result); + } failure:nil]; + + In the above example, request and response mapping configurations were described for a simple data model and then used to perform a basic POST operation and map the results. An arbitrary number of request and response descriptors may be added to the manager to accommodate your application's needs. + + ## Multi-object Parameterization + + The object manager provides support for the parameterization of multiple objects provided as an array. The `requestWithObject:method:path:parameters:` and `multipartFormRequestWithObject:method:path:parameters:constructingBodyWithBlock:` methods can parameterize an array of objects for you provided that the `RKRequestDescriptor` objects are configured in a compatible way. The rules for multi-object parameterization are simple: + + 1. If a `nil` root key path is used, then it must be used for all objects in the array. This is because the objects will be parameterized into a dictionary and then each dictionary will be added to an array. This array is then serialized for transport, so objects parameterized to a non-nil key path cannot be merged with the array. + 1. If a `nil` root key path is used to parameterize the array of objects, then you cannot provide additional parameters to be merged with the request. This is again because you cannot merge a dictionary with an array. + + If non-nil key paths are used, then each object will be set in the parameters dictionary at the specified key path. If more than one object uses the same root key path, then the parameters will be combined into an array for transport. + + ## MIME Types + + MIME Types serve an important function to the object manager. They are used to identify how content is to be serialized when constructing request bodies and also used to set the 'Accept' header for content negotiation. RestKit aspires to be content type agnostic by leveraging the pluggable `RKMIMESerialization` class to handle content serialization and deserialization. + + ## Routing + + Routing is the process of generating an `NSURL` appropriate for a particular HTTP server request interaction. Using routing instead of hard-coding paths enables centralization of configuration and allows the developer to focus on what they want done rather than the details of how to do it. Changes to the URL structure in the application can be made in one place. Routes can also be useful in testing, as they permit for the changing of paths at run-time. + + Routing interfaces are provided by the `RKRouter` class. Each object manager is in initialized with an `RKRouter` object with a baseURL equal to the baseURL of the underlying `AFHTTPClient` object. Each `RKRouter` instance maintains an `RKRouteSet` object that manages a collection of `RKRoute` objects. Routes are defined in terms of a path pattern. + + There are three types of routes currently supported: + + 1. Class Routes. Class routes are configured to target a given object class and HTTP request method. For example, we might route the HTTP `GET` for a `User` class to the path pattern `@"/users/:userID"`. + 1. Relationship Routes. Relationship routes identify the path appropriate for performing a request for an object that is related to another object. For example, each `User` may have many friends. This might be routed as a relationship route for the `User` class with the name `@"friends"` to the path pattern `@"/users/:userID/friends"`. + 1. Named Routes. Names routes bind an arbitrary name to a path. For example, there might be an action to follow another user that could be added as a named route with the name `@"follow_user"` that generates a `POST` to the path pattern `@"/users/:userID/follow"`. + + To better understand these concepts, please consider the following example code for configuring the above routing examples: + + RKObjectManager *manager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:@"http://restkit.org"]]; + + // Class Route + [manager.router.routeSet addRoute:[RKRoute routeWithClass:[User class] pathPattern:@"/users/:userID" method:RKRequestMethodGET]]; + + // Relationship Route + [manager.router.routeSet addRoute:[RKRoute routeWithRelationshipName:@"friends" objectClass:[User class] pathPattern:@"/users/:userID/friends" method:RKRequestMethodGET]]; + + // Named Route + [manager.router.routeSet addRoute:[RKRoute routeWithName:@"follow_user" pathPattern:@"/users/:userID/follow" method:RKRequestMethodPOST]]; + + Once configured, routes will be consulted by the object manager whenever the path parameter provided to a method is given as nil. For example, invoking the following code would result in a `GET` to the path `@"/users/1234"`: + + User *user = [User new]; + user.userID = 1234; + [manager getObject:user path:nil parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *result) { + // Request + } failure:nil]; + + Routes can also be explicitly used to construct `NSMutableURLRequest` objects and are referenced explicitly in a few object request operation methods: + + 1. `requestWithObject:method:path:parameters:` - Consults routing when path is nil. + 1. `multipartFormRequestWithObject:method:path:parameters:constructingBodyWithBlock:` - Consults routing when path is nil. + 1. `requestWithPathForRouteNamed:object:parameters:` - Explicitly retrieves the route with the given name. + 1. `getObjectsAtPathForRelationship:ofObject:parameters:success:failure:` - Explicitly retrieves the route for the given name and object class. + 1. `getObjectsAtPathForRouteNamed:object:parameters:success:failure:` - Explicitly retrieves the route for the given name. + + Please see the documentation for `RKRouter`, `RKRouteSet`, and `RKRoute` for more details about the routing classes. + + ## Metadata Mapping + + The `RKObjectManager` class has integrated support for metadata mapping. Metdata mapping enables the object mapping of supplemental information external to the object representation loaded via an HTTP response. Object request operations constructed by the manager make the following metadata key paths available for mapping: + + 1. `@metadata.routing.parameters` - A dictionary whose keys are the key paths matched from the path pattern of the `RKRoute` object used to construct the request URL and whose values are taken by evaluating the key path against the object interpolated with the route. Only available when routing was used to construct the request URL. + 1. `@metadata.routing.route` - The route object used to construct the request URL. + + Please refer to the documentation accompanying `RKMappingOperation` for more details on metadata mapping. + + ## Core Data + + RestKit features deep integration with Apple's Core Data persistence framework. The object manager provides access to this integration by creating `RKManagedObjectRequestOperation` objects when an attempt is made to interact with a resource that has been mapped using an `RKEntityMapping`. To utilize the Core Data integration, the object manager must be provided with a fully configured `RKManagedObjectStore` object. The `RKManagedObjectStore` provides access to the `NSManagedObjectModel` and `NSManagedObjectContext` objects required to peform object mapping that targets a Core Data entity. + + Please see the documentation for `RKManagedObjectStore`, `RKEntityMapping`, and `RKManagedObjectRequestOperation` for in depth information about Core Data in RestKit. + + ## Customization & Subclassing Notes + + The object manager is designed to support subclassing. The default behaviors can be altered and tailored to the specific needs of your application easily by manipulating a few core methods: + + * `requestWithObject:method:path:parameters:` - Used to construct all `NSMutableURLRequest` objects used by the manager. + * `objectRequestOperationWithRequest:success:failure:` - Used to construct all non-managed object request operations for the manager. Provide a subclass implementation if you wish to alter the behavior of all unmanaged object request operations. + * `managedObjectRequestOperationWithRequest:managedObjectContext:success:failure:` - Used to construct all managed object request operations for the manager. Provide a subclass implementation if you wish to alter the behavior of all managed object request operations. + * `appropriateObjectRequestOperationWithObject:method:path:parameters:` - Used to construct all object request operations for the manager, both managed and unmanaged. Invokes either `objectRequestOperationWithRequest:success:failure:` or `managedObjectRequestOperationWithRequest:managedObjectContext:success:failure:` to construct the actual request. Provide a subclass implementation to alter behaviors for all object request operations constructed by the manager. + * `enqueueObjectRequestOperation:` - Invoked to enqueue all operations constructed by the manager that are to be started as soon as possible. Provide a subclass implementation if you wish to work with object request operations as they are be enqueued. + + If you wish to more specifically customize the behavior of the lower level HTTP details, you have several options. All HTTP requests made by the `RKObjectManager` class are made with an instance of the `RKHTTPRequestOperation` class, which is a subclass of the `AFHTTPRequestOperation` class from AFNetworking. This operation class implements the `NSURLConnectionDelegate` and `NSURLConnectionDataDelegate` protocols and as such, has full access to all details of the HTTP request/response cycle exposed by `NSURLConnection`. You can provide the object manager with your own custom subclass of `RKHTTPRequestOperation` to the manager via the `registerRequestOperationClass:` method and all HTTP requests made through the manager will pass through your operation. + + You can also customize the HTTP details at the AFNetworking level by subclassing `AFHTTPClient` and using an instance of your subclassed client to initialize the manager. + + @warning Note that when subclassing `AFHTTPClient` to change object manager behaviors it is not possible to alter the paramters of requests that are constructed on behalf of the manager. This is because the object manager handles its own serialization and construction of the request body, but defers to the `AFHTTPClient` for all other details (such as default HTTP headers, etc). + + @see `RKObjectRequestOperation` + @see `RKRouter` + @see `RKPathMatcher` + @see `RKMIMETypeSerialization` + */ +@interface RKObjectManager : NSObject + +///---------------------------------------------- +/// @name Configuring the Shared Manager Instance +///---------------------------------------------- + +/** + Return the shared instance of the object manager + + @return The shared manager instance. + */ ++ (instancetype)sharedManager; + +/** + Set the shared instance of the object manager + + @param manager The new shared manager instance. + */ ++ (void)setSharedManager:(RKObjectManager *)manager; + +///------------------------------------- +/// @name Initializing an Object Manager +///------------------------------------- + +/** + Creates and returns a new `RKObjectManager` object initialized with a new `AFHTTPClient` object that was in turn initialized with the given base URL. The RestKit defaults are applied to the object manager. + + When initialized with a base URL, the returned object manager will have a `requestSerializationMIMEType` with the value of `RKMIMETypeFormURLEncoded` and the underlying `HTTPClient` will have a default value for the 'Accept' header set to `RKMIMETypeJSON`, and the `AFJSONRequestOperation` class will be registered. + + @param baseURL The base URL with which to initialize the `AFHTTPClient` object + @return A new `RKObjectManager` initialized with an `AFHTTPClient` that was initialized with the given baseURL. + */ ++ (instancetype)managerWithBaseURL:(NSURL *)baseURL; + +/** + Initializes the receiver with the given AFNetworking HTTP client object, adopting the network configuration from the client. + + This is the designated initializer. If the `sharedManager` instance is `nil`, the receiver will be set as the `sharedManager`. The default headers and parameter encoding of the given HTTP client are adopted by the receiver to initialize the values of the `defaultHeaders` and `requestSerializationMIMEType` properties. + + @param client The AFNetworking HTTP client with which to initialize the receiver. + @return The receiver, initialized with the given client. + */ +- (instancetype)initWithHTTPClient:(AFHTTPClient *)client NS_DESIGNATED_INITIALIZER; + +///------------------------------------------ +/// @name Accessing Object Manager Properties +///------------------------------------------ + +/** + The AFNetworking HTTP client with which the receiver makes requests. + */ +@property (nonatomic, strong, readwrite) AFHTTPClient *HTTPClient; + +/** + The base URL of the underlying HTTP client. + */ +@property (nonatomic, readonly) NSURL *baseURL; + +/** + The default HTTP headers for all `NSURLRequest` objects constructed by the object manager. + + The returned dictionary contains all of the default headers set on the underlying `AFHTTPClient` object and the value of the 'Accept' header set on the object manager, if any. + + @see `setAcceptHeaderWithMIMEType:` + */ +@property (nonatomic, readonly) NSDictionary *defaultHeaders; + +/** + The operation queue which manages operations enqueued by the object manager. + */ +@property (nonatomic, strong) NSOperationQueue *operationQueue; + +/** + The router used to generate URL objects for routable requests created by the manager. + + @see `RKRouter` + @see `RKRoute` + */ +@property (nonatomic, strong) RKRouter *router; + +///-------------------------------------------------- +/// @name Configuring Request and Response MIME Types +///-------------------------------------------------- + +/** + The MIME Type to serialize request parameters into when constructing request objects. + + The value of the `requestSerializationMIMEType` is used to obtain an appropriate `RKSerialization` conforming class from the `RKMIMESerialization` interface. Parameterized objects and dictionaries of parameters are then serialized for transport using the class registered for the MIME Type. By default, the value is `RKMIMETypeFormURLEncoded` which means that the request body of all `POST`, `PUT`, and `PATCH` requests will be sent in the URL encoded format. This is analagous to submitting an HTML form via a web browser. Other common formats include `RKMIMETypeJSON`, which will cause request bodies to be encoded as JSON. + + The value given for the `requestSerializationMIMEType` must correspond to a MIME Type registered via `[RKMIMETypeSerialization registerClass:forMIMEType:]`. Implementations are provided by default for `RKMIMETypeFormURLEncoded` and `RKMIMETypeJSON`. + + **Default**: `RKMIMETypeFormURLEncoded` or the value of the parameter encoding for the underlying `AFHTTPClient`. + */ +@property (nonatomic, strong) NSString *requestSerializationMIMEType; + +/** + Sets a default header on the HTTP client for the HTTP "Accept" header to specify the preferred serialization format for retrieved data. + + This method is a convenience method whose implementation is equivalent to the following example code: + + [manager.HTTPClient setDefaultHeader:@"Accept" value:MIMEType]; + + @param MIMEType The MIME Type to set as the value for the HTTP "Accept" header. + */ +- (void)setAcceptHeaderWithMIMEType:(NSString *)MIMEType; + +///------------------------------- +/// @name Creating Request Objects +///------------------------------- + +/** + Creates and returns an `NSMutableURLRequest` object with a given object, method, path, and parameters. + + The manager is searched for an `RKRequestDescriptor` object with an objectClass that matches the class of the given object. If found, the matching request descriptor and object are used to build a parameterization of the object's attributes using the `RKObjectParameterization` class if the request method is a `POST`, `PUT`, or `PATCH`. The parameterized representation of the object is reverse merged with the given parameters dictionary, if any, and then serialized and set as the request body. If the HTTP method is `GET` or `DELETE`, the object will not be parameterized and the given parameters, if any, will be used to construct a url-encoded query string that is appended to the request's URL. + + If the given path is nil, the router is searched for a class route with the class of the object andthe method. The path pattern of the retrieved route is interpolated with the object and the resulting path is appended to the HTTP client's base URL and used as the request URL. + + @param object The object with which to construct the request. For the `POST`, `PUT`, and `PATCH` request methods, the object will parameterized using the `RKRequestDescriptor` for the object. + @param method The HTTP method for the request, such as `GET`, `POST`, `PUT`, or `DELETE`. + @param path The path to be appended to the HTTP client's base URL and used as the request URL. If nil, the router is consulted. + @param parameters The parameters to be either set as a query string for `GET` requests, or reverse merged with the parameterization of the object and set as the request HTTP body. + + @return An `NSMutableURLRequest` object. + @see RKObjectParameterization + @see RKRouter + */ +- (NSMutableURLRequest *)requestWithObject:(id)object + method:(RKRequestMethod)method + path:(NSString *)path + parameters:(NSDictionary *)parameters; + +/** + Creates an `NSMutableURLRequest` object with the specified HTTP method and path, and constructs a `multipart/form-data` HTTP body, using the specified parameters and multipart form data block. See http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4.2 + + This method wraps the underlying `AFHTTPClient` method `multipartFormRequestWithMethod:path:parameters:constructingBodyWithBlock` and adds routing and object parameterization. + + @param object The object with which to construct the request. For the `POST`, `PUT`, and `PATCH` request methods, the object will parameterized using the `RKRequestDescriptor` for the object. + @param method The HTTP method for the request, such as `GET`, `POST`, `PUT`, or `DELETE`. + @param path The path to be appended to the HTTP client's base URL and used as the request URL. If nil, the router is consulted. + @param parameters The parameters to be either set as a query string for `GET` requests, or reverse merged with the parameterization of the object and set as the request HTTP body. + @param block A block that takes a single argument and appends data to the HTTP body. The block argument is an object adopting the `AFMultipartFormData` protocol. This can be used to upload files, encode HTTP body as JSON or XML, or specify multiple values for the same parameter, as one might for array values. + @return An `NSMutableURLRequest` object. + @warning An exception will be raised if the specified method is not `POST`, `PUT` or `DELETE`. + @see [AFHTTPClient multipartFormRequestWithMethod:path:parameters:constructingBodyWithBlock] + */ +- (NSMutableURLRequest *)multipartFormRequestWithObject:(id)object + method:(RKRequestMethod)method + path:(NSString *)path + parameters:(NSDictionary *)parameters + constructingBodyWithBlock:(void (^)(id <AFMultipartFormData> formData))block; + +/** + Creates an `NSMutableURLRequest` object with the `NSURL` returned by the router for the given route name and object and the given parameters. + + The implementation invokes `requestWithObject:method:path:parameters:` after constructing the path with the given route. + + @param routeName The name of the route object containing the path pattern which is to be interpolated against the given object, appended to the HTTP client's base URL and used as the request URL. + @param object The object with which to interpolate the path pattern of the named route. Can be nil. + @param parameters The parameters to be either set as a query string for `GET` requests, or the request HTTP body. + @return An `NSMutableRequest` object. + + @see `requestWithObject:method:path:parameters` + */ +- (NSMutableURLRequest *)requestWithPathForRouteNamed:(NSString *)routeName + object:(id)object + parameters:(NSDictionary *)parameters; +/** + Creates an `NSMutableURLRequest` object with the `NSURL` returned by the router for the relationship of the given object and the given parameters. + + The implementation invokes `requestWithObject:method:path:parameters:` after constructing the path with the given route. + + Creates an `RKObjectRequestOperation` with a `GET` request for the relationship with the given name of the given object, and enqueues it to the manager's operation queue. + + @param relationship The name of the relationship being loaded. Used to retrieve the `RKRoute` object from the router for the given object's class and the relationship name. Cannot be nil. + @param object The object for which related objects are being loaded. Evaluated against the `RKRoute` for the relationship for the object's class with the given name to compute the path. Cannot be nil. + @param method The HTTP method for the request. + @param parameters The parameters to be encoded and appended as the query string for the request URL, or parameterized and set as the request body. May be nil. + @return An `NSMutableURLRequest` object for the specified relationship. + + @raises NSInvalidArgumentException Raised if no route is configured for a relationship of the given object's class with the given name. + @see `requestWithObject:method:path:parameters` + */ +- (NSMutableURLRequest *)requestWithPathForRelationship:(NSString *)relationship + ofObject:(id)object + method:(RKRequestMethod)method + parameters:(NSDictionary *)parameters; + +///----------------------------------------- +/// @name Creating Object Request Operations +///----------------------------------------- + +/** + Attempts to register a subclass of `RKHTTPRequestOperation` or `RKObjectRequestOperation`, adding it to a list of classes that are consulted each time the receiver needs to construct an HTTP or object request operation with a URL request. + + When `objectRequestOperationWithRequest:success:failure:` or `managedObjectRequestOperationWithRequest:managedObjectContext:success:failure:` is invoked, each registered subclass is consulted to see if it can handle the request. The first class to return `YES` when sent a `+ canProcessRequest:` message is used to create an operation using `initWithHTTPRequestOperation:responseDescriptors:`. The type of HTTP request operation used to initialize the object request operation is determined by evaluating the subclasses of `RKHTTPRequestOperation` registered via `registerRequestOperationClass:` and defaults to `RKHTTPRequestOperation`. + + There is no guarantee that all registered classes will be consulted. The object manager will only consider direct subclasses of `RKObjectRequestOperation` when `objectRequestOperationWithRequest:success:failure` is called and will only consider subclasses of `RKManagedObjectRequestOperation` when `managedObjectRequestOperationWithRequest:managedObjectContext:success:failure:` is called. If you wish to map a mixture of managed and unmanaged objects within the same object request operation you must register a `RKManagedObjectRequestOperation` subclass. Classes are consulted in the reverse order of their registration. Attempting to register an already-registered class will move it to the top of the list. + + @param operationClass The subclass of `RKHTTPRequestOperation` or `RKObjectRequestOperation` to register. + @return `YES` if the given class was registered successfully, else `NO`. The only failure condition is if `operationClass` is not a subclass of `RKHTTPRequestOperation` or `RKObjectRequestOperation`. + */ +- (BOOL)registerRequestOperationClass:(Class)operationClass; + +/** + Unregisters the specified subclass of `RKHTTPRequestOperation` or `RKObjectRequestOperation` from the list of classes consulted when `objectRequestOperationWithRequest:success:failure:` or `managedObjectRequestOperationWithRequest:managedObjectContext:success:failure:` is called. + + @param operationClass The subclass of `RKHTTPRequestOperation` or `RKObjectRequestOperation` to unregister. + */ +- (void)unregisterRequestOperationClass:(Class)operationClass; + +/** + Creates an `RKObjectRequestOperation` operation with the given request and sets the completion block with the given success and failure blocks. + + In order to determine what kind of operation is created, each registered `RKObjectRequestOperation` subclass is consulted (in reverse order of when they were specified) to see if it can handle the specific request. The first class to return `YES` when sent a `canProcessRequest:` message is used to create an operation using `initWithHTTPRequestOperation:responseDescriptors:`. The type of HTTP request operation used to initialize the object request operation is determined by evaluating the subclasses of `RKHTTPRequestOperation` registered via `registerRequestOperationClass:` and defaults to `RKHTTPRequestOperation`. + + @param request The request object to be loaded asynchronously during execution of the operation. + @param success A block object to be executed when the request operation finishes successfully. This block has no return value and takes two arguments: the created object request operation and the `RKMappingResult` object created by object mapping the response data of request. + @param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the resonse data. This block has no return value and takes two arguments:, the created request operation and the `NSError` object describing the network or parsing error that occurred. + @return An `RKObjectRequestOperation` object that is ready to be sent. + + @warning Instances of `RKObjectRequestOperation` are not capable of mapping the loaded `NSHTTPURLResponse` into a Core Data entity. Use an instance of `RKManagedObjectRequestOperation` if the response is to be mapped using an `RKEntityMapping`. + */ +- (RKObjectRequestOperation *)objectRequestOperationWithRequest:(NSURLRequest *)request + success:(void (^)(RKObjectRequestOperation *operation, RKMappingResult *mappingResult))success + failure:(void (^)(RKObjectRequestOperation *operation, NSError *error))failure; + +/** + Creates an `RKManagedObjectRequestOperation` operation with the given request and managed object context, and sets the completion block with the given success and failure blocks. + + The given managed object context given will be used as the parent context of the private managed context in which the response is mapped and will be used to fetch the results upon invocation of the success completion block. + + In order to determine what kind of operation is created, each registered `RKManagedObjectRequestOperation` subclass is consulted (in reverse order of when they were specified) to see if it can handle the specific request. The first class to return `YES` when sent a `canProcessRequest:` message is used to create an operation using `initWithHTTPRequestOperation:responseDescriptors:`. The type of HTTP request operation used to initialize the object request operation is determined by evaluating the subclasses of `RKHTTPRequestOperation` registered via `registerRequestOperationClass:` and defaults to `RKHTTPRequestOperation`. + + @param request The request object to be loaded asynchronously during execution of the operation. + @param managedObjectContext The managed object context with which to associate the operation. This context will be used as the parent context of a new operation local `NSManagedObjectContext` with the `NSPrivateQueueConcurrencyType` concurrency type. Upon success, the private context will be saved and changes resulting from the object mapping will be 'pushed' to the given context. + @param success A block object to be executed when the request operation finishes successfully. This block has no return value and takes two arguments: the created object request operation and the `RKMappingResult` object created by object mapping the response data of request. + @param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the resonse data. This block has no return value and takes two arguments:, the created request operation and the `NSError` object describing the network or parsing error that occurred. + @return An `RKObjectRequestOperation` object that is ready to be sent. + + @see `RKManagedObjectRequestOperation` + */ +#ifdef RKCoreDataIncluded +- (RKManagedObjectRequestOperation *)managedObjectRequestOperationWithRequest:(NSURLRequest *)request + managedObjectContext:(NSManagedObjectContext *)managedObjectContext + success:(void (^)(RKObjectRequestOperation *operation, RKMappingResult *mappingResult))success + failure:(void (^)(RKObjectRequestOperation *operation, NSError *error))failure; +#endif + +/** + Creates and returns an object request operation of the appropriate type for the given object, request method, path, and parameters. + + The type of object request operation created is determined by evaluating the type of the object given and examining the list of `RKResponseDescriptor` objects added to the manager. + + If the given object is non-nil and inherits from `NSManagedObject`, then an instance of `RKManagedObjectRequestOperation` is returned. + + If the given object is nil, then the `RKResponseDescriptor` objects added to the manager are evaluated to determine the type of operation created. In this case, the path of the operation is used to filter the set of `RKResponseDescriptor` objects to those that may be used to map the response. If the path is nil, the router is consulted to determine an appropriate path with which to perform the matching. If the filtered array of matching response descriptors defines a mapping configuration with an `RKEntityMapping` object, then an `RKManagedObjectRequestOperation` is returned; otherwise an `RKObjectRequestOperation` is returned. + + If an `RKManagedObjectRequestOperation` operation is created, the managed object context used will be the `mainQueueManagedObjectContext` of the manager's `managedObjectStore`. + + @param object The object with which to construct the object request operation. May be nil. + @param method The request method for the request. + @param path The path to be appended to the HTTP client's baseURL and set as the URL of the request. If nil, the router is consulted. + @param parameters The parameters to be either set as a query string for `GET` requests, or reverse merged with the parameterization of the object and set as the request HTTP body. + + @return A newly created `RKObjectRequestOperation` or `RKManagedObjectRequest` operation as deemed appropriate by the manager for the given parameters. + @warning The given object must be a single object instance. Collections are not yet supported. + + @see `requestWithObject:method:path:parameters` + */ +- (id)appropriateObjectRequestOperationWithObject:(id)object + method:(RKRequestMethod)method + path:(NSString *)path + parameters:(NSDictionary *)parameters; + +///-------------------------------------------------- +/// @name Managing Enqueued Object Request Operations +///-------------------------------------------------- + +/** + Enqueues an `RKObjectRequestOperation` to the object manager's operation queue. + + @param objectRequestOperation The object request operation to be enqueued. + */ +- (void)enqueueObjectRequestOperation:(RKObjectRequestOperation *)objectRequestOperation; + +/** + Returns an array of operations in the object manager's operation queue whose requests match the specified HTTP method and path pattern. + + Paths are matches against the `path` of the `NSURL` of the `NSURLRequest` of each `RKObjectRequestOperation` contained in the receiver's operation queue using a `RKPathMatcher` object. + + @param method The HTTP method to match for the cancelled requests, such as `RKRequestMethodGET`, `RKRequestMethodPOST`, `RKRequestMethodPUT`, `RKRequestMethodPatch`, or `RKRequestMethodDELETE`. If `RKRequestMethodAny`, all object request operations with URLs matching the given path pattern will be cancelled. Multiple methods may be specified by using a bitwise OR operation. + @param pathPattern The pattern to match against the path of the request URL for executing object request operations considered for cancellation. + @return A new array containing all enqueued `RKObjectRequestOperation` objects that match the given HTTP method and path pattern. + @see `RKPathMatcher` + */ +- (NSArray *)enqueuedObjectRequestOperationsWithMethod:(RKRequestMethod)method matchingPathPattern:(NSString *)pathPattern; + +/** + Cancels all operations in the object manager's operation queue whose requests match the specified HTTP method and path pattern. + + Paths are matches against the `path` of the `NSURL` of the `NSURLRequest` of each `RKObjectRequestOperation` contained in the receiver's operation queue using a `RKPathMatcher` object. + + @param method The HTTP method to match for the cancelled requests, such as `RKRequestMethodGET`, `RKRequestMethodPOST`, `RKRequestMethodPUT`, `RKRequestMethodPatch`, or `RKRequestMethodDELETE`. If `RKRequestMethodAny`, all object request operations with URLs matching the given path pattern will be cancelled. + @param pathPattern The pattern to match against the path of the request URL for executing object request operations considered for cancellation. + + @see `RKPathMatcher` + */ +- (void)cancelAllObjectRequestOperationsWithMethod:(RKRequestMethod)method matchingPathPattern:(NSString *)pathPattern; + +///----------------------------------------- +/// @name Batching Object Request Operations +///----------------------------------------- + +/** + Creates and enqueues an `RKObjectRequestOperation` to the object manager's operation queue for each specified object into a batch. Each object request operation is built by evaluating the object against the given route to construct a request path and then invoking `appropriateObjectRequestOperationWithObject:method:path:parameters:`. When each object request operation finishes, the specified progress block is executed, until all of the request operations have finished, at which point the completion block also executes. + + @warning Note that the route type is significant in how that the object request operation is constructed. If the given route is a class route, then the `targetObject` of the operation will be set to the object for which the operation is being constructed. For named routes and relationship routes, the target object is `nil`. + + @param route The route specifying the request method and the path pattern with which to construct the request for each object object request operation in the batch. + @param objects The set of objects for which to enqueue a batch of object request operations. + @param progress A block object to be executed when an object request operation completes. This block has no return value and takes two arguments: the number of finished operations and the total number of operations initially executed. + @param completion A block object to be executed when the object request operations complete. This block has no return value and takes one argument: the list of operations executed. + + @see `[RKObjectManager enqueueBatchOfObjectRequestOperations:progress:completion]` + @see `RKRoute` + */ +- (void)enqueueBatchOfObjectRequestOperationsWithRoute:(RKRoute *)route + objects:(NSArray *)objects + progress:(void (^)(NSUInteger numberOfFinishedOperations, + NSUInteger totalNumberOfOperations))progress + completion:(void (^)(NSArray *operations))completion; + +/** + Enqueues a set of `RKObjectRequestOperation` to the object manager's operation queue. + + @param operations The set of object request operations to be enqueued. + @param progress A block object to be executed when an object request operation completes. This block has no return value and takes two arguments: the number of finished operations and the total number of operations initially executed. + @param completion A block object to be executed when the object request operations complete. This block has no return value and takes one argument: the list of operations executed. + + */ +- (void)enqueueBatchOfObjectRequestOperations:(NSArray *)operations + progress:(void (^)(NSUInteger numberOfFinishedOperations, + NSUInteger totalNumberOfOperations))progress + completion:(void (^)(NSArray *operations))completion; + +///------------------------------------- +/// @name Making Object Requests by Path +///------------------------------------- + +/** + Creates an `RKObjectRequestOperation` with a `GET` request with a URL for the given path, and enqueues it to the manager's operation queue. + + The type of object request operation created is determined by invoking `appropriateObjectRequestOperationWithObject:method:path:parameters:`. + + @param path The path to be appended to the HTTP client's base URL and used as the request URL. + @param parameters The parameters to be encoded and appended as the query string for the request URL. + @param success A block object to be executed when the object request operation finishes successfully. This block has no return value and takes two arguments: the created object request operation and the `RKMappingResult` object created by object mapping the response data of request. + @param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the resonse data. This block has no return value and takes two arguments:, the created request operation and the `NSError` object describing the network or parsing error that occurred. + + @see [RKObjectManager appropriateObjectRequestOperationWithObject:method:path:parameters:] + */ +- (void)getObjectsAtPath:(NSString *)path + parameters:(NSDictionary *)parameters + success:(void (^)(RKObjectRequestOperation *operation, RKMappingResult *mappingResult))success + failure:(void (^)(RKObjectRequestOperation *operation, NSError *error))failure; + +/** + Creates an `RKObjectRequestOperation` with a `GET` request for the relationship with the given name of the given object, and enqueues it to the manager's operation queue. + + The type of object request operation created is determined by invoking `appropriateObjectRequestOperationWithObject:method:path:parameters:`. + + @param relationshipName The name of the relationship being loaded. Used to retrieve the `RKRoute` object from the router for the given object's class and the relationship name. Cannot be nil. + @param object The object for which related objects are being loaded. Evaluated against the `RKRoute` for the relationship for the object's class with the given name to compute the path. Cannot be nil. + @param parameters The parameters to be encoded and appended as the query string for the request URL. May be nil. + @param success A block object to be executed when the object request operation finishes successfully. This block has no return value and takes two arguments: the created object request operation and the mapped result created from object mapping the response data of request. + @param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the resonse data. This block has no return value and takes two arguments:, the created request operation and the `NSError` object describing the network or parsing error that occurred. + + @raises NSInvalidArgumentException Raised if no route is configured for a relationship of the given object's class with the given name. + @see [RKRouter URLForRelationship:ofObject:method:] + @see [RKObjectManager appropriateObjectRequestOperationWithObject:method:path:parameters:] + */ +- (void)getObjectsAtPathForRelationship:(NSString *)relationshipName + ofObject:(id)object + parameters:(NSDictionary *)parameters + success:(void (^)(RKObjectRequestOperation *operation, RKMappingResult *mappingResult))success + failure:(void (^)(RKObjectRequestOperation *operation, NSError *error))failure; + +/** + Creates an `RKObjectRequestOperation` with a `GET` request for the URL returned by the router for the given route name, and enqueues it to the manager's operation queue. + + The type of object request operation created is determined by invoking `appropriateObjectRequestOperationWithObject:method:path:parameters:`. + + @param routeName The name of the route being loaded. Used to retrieve the `RKRoute` object from the router with the given name. Cannot be nil. + @param object The object to be interpolated against the path pattern of the `RKRoute` object retrieved with the given name. Used to compute the path to be appended to the HTTP client's base URL and used as the request URL. May be nil. + @param parameters The parameters to be encoded and appended as the query string for the request URL. May be nil. + @param success A block object to be executed when the object request operation finishes successfully. This block has no return value and takes two arguments: the created object request operation and the mapped result created from object mapping the response data of request. + @param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the resonse data. This block has no return value and takes two arguments:, the created request operation and the `NSError` object describing the network or parsing error that occurred. + + @raises NSInvalidArgumentException Raised if no route is configured with the given name or the route returned specifies an HTTP method other than `GET`. + @see [RKRouter URLForRouteNamed:method:object:] + @see [RKObjectManager appropriateObjectRequestOperationWithObject:method:path:parameters:] + */ +- (void)getObjectsAtPathForRouteNamed:(NSString *)routeName + object:(id)object + parameters:(NSDictionary *)parameters + success:(void (^)(RKObjectRequestOperation *operation, RKMappingResult *mappingResult))success + failure:(void (^)(RKObjectRequestOperation *operation, NSError *error))failure; + +///------------------------------------------- +/// @name Making Object Requests for an Object +///------------------------------------------- + +/** + Creates an `RKObjectRequestOperation` with a `GET` request for the given object, and enqueues it to the manager's operation queue. + + The type of object request operation created is determined by invoking `appropriateObjectRequestOperationWithObject:method:path:parameters:`. + + @param object The object with which to construct the object request operation. If `nil`, then the path must be provided. + @param path The path to be appended to the HTTP client's base URL and used as the request URL. If nil, the request URL will be obtained by consulting the router for a route registered for the given object's class and the `RKRequestMethodGET` request method. + @param parameters The parameters to be encoded and appended as the query string for the request URL. + @param success A block object to be executed when the object request operation finishes successfully. This block has no return value and takes two arguments: the created object request operation and the `RKMappingResult` object created by object mapping the response data of request. + @param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the resonse data. This block has no return value and takes two arguments:, the created request operation and the `NSError` object describing the network or parsing error that occurred. + + @see [RKRouter URLForObject:method:] + @see [RKObjectManager appropriateObjectRequestOperationWithObject:method:path:parameters:] + */ +- (void)getObject:(id)object + path:(NSString *)path + parameters:(NSDictionary *)parameters + success:(void (^)(RKObjectRequestOperation *operation, RKMappingResult *mappingResult))success + failure:(void (^)(RKObjectRequestOperation *operation, NSError *error))failure; + +/** + Creates an `RKObjectRequestOperation` with a `POST` request for the given object, and enqueues it to the manager's operation queue. + + @param object The object with which to construct the object request operation. If `nil`, then the path must be provided. + @param path The path to be appended to the HTTP client's base URL and used as the request URL. If nil, the request URL will be obtained by consulting the router for a route registered for the given object's class and the `RKRequestMethodPOST` method. + @param parameters The parameters to be reverse merged with the parameterization of the given object and set as the request body. + @param success A block object to be executed when the object request operation finishes successfully. This block has no return value and takes two arguments: the created object request operation and the `RKMappingResult` object created by object mapping the response data of request. + @param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the resonse data. This block has no return value and takes two arguments:, the created request operation and the `NSError` object describing the network or parsing error that occurred. + + @see [RKRouter URLForObject:method:] + @see [RKObjectManager appropriateObjectRequestOperationWithObject:method:path:parameters:] + */ +- (void)postObject:(id)object + path:(NSString *)path + parameters:(NSDictionary *)parameters + success:(void (^)(RKObjectRequestOperation *operation, RKMappingResult *mappingResult))success + failure:(void (^)(RKObjectRequestOperation *operation, NSError *error))failure; + +/** + Creates an `RKObjectRequestOperation` with a `PUT` request for the given object, and enqueues it to the manager's operation queue. + + @param object The object with which to construct the object request operation. If `nil`, then the path must be provided. + @param path The path to be appended to the HTTP client's base URL and used as the request URL. If nil, the request URL will be obtained by consulting the router for a route registered for the given object's class and the `RKRequestMethodPUT` method. + @param parameters The parameters to be reverse merged with the parameterization of the given object and set as the request body. + @param success A block object to be executed when the object request operation finishes successfully. This block has no return value and takes two arguments: the created object request operation and the `RKMappingResult` object created by object mapping the response data of request. + @param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the resonse data. This block has no return value and takes two arguments:, the created request operation and the `NSError` object describing the network or parsing error that occurred. + + @see [RKRouter URLForObject:method:] + @see [RKObjectManager appropriateObjectRequestOperationWithObject:method:path:parameters:] + */ +- (void)putObject:(id)object + path:(NSString *)path + parameters:(NSDictionary *)parameters + success:(void (^)(RKObjectRequestOperation *operation, RKMappingResult *mappingResult))success + failure:(void (^)(RKObjectRequestOperation *operation, NSError *error))failure; + +/** + Creates an `RKObjectRequestOperation` with a `PATCH` request for the given object, and enqueues it to the manager's operation queue. + + @param object The object with which to construct the object request operation. If `nil`, then the path must be provided. + @param path The path to be appended to the HTTP client's base URL and used as the request URL. If nil, the request URL will be obtained by consulting the router for a route registered for the given object's class and the `RKRequestMethodPATCH` method. + @param parameters The parameters to be reverse merged with the parameterization of the given object and set as the request body. + @param success A block object to be executed when the object request operation finishes successfully. This block has no return value and takes two arguments: the created object request operation and the `RKMappingResult` object created by object mapping the response data of request. + @param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the resonse data. This block has no return value and takes two arguments:, the created request operation and the `NSError` object describing the network or parsing error that occurred. + + @see [RKRouter URLForObject:method:] + @see [RKObjectManager appropriateObjectRequestOperationWithObject:method:path:parameters:] + */ +- (void)patchObject:(id)object + path:(NSString *)path + parameters:(NSDictionary *)parameters + success:(void (^)(RKObjectRequestOperation *operation, RKMappingResult *mappingResult))success + failure:(void (^)(RKObjectRequestOperation *operation, NSError *error))failure; + +/** + Creates an `RKObjectRequestOperation` with a `DELETE` request for the given object, and enqueues it to the manager's operation queue. + + The type of object request operation created is determined by invoking `appropriateObjectRequestOperationWithObject:method:path:parameters:`. + + @param object The object with which to construct the object request operation. If `nil`, then the path must be provided. + @param path The path to be appended to the HTTP client's base URL and used as the request URL. If nil, the request URL will be obtained by consulting the router for a route registered for the given object's class and the `RKRequestMethodDELETE` request method. + @param parameters The parameters to be encoded and appended as the query string for the request URL. + @param success A block object to be executed when the object request operation finishes successfully. This block has no return value and takes two arguments: the created object request operation and the `RKMappingResult` object created by object mapping the response data of request. + @param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the resonse data. This block has no return value and takes two arguments:, the created request operation and the `NSError` object describing the network or parsing error that occurred. + + @see [RKRouter URLForObject:method:] + @see [RKObjectManager appropriateObjectRequestOperationWithObject:method:path:parameters:] + */ +- (void)deleteObject:(id)object + path:(NSString *)path + parameters:(NSDictionary *)parameters + success:(void (^)(RKObjectRequestOperation *operation, RKMappingResult *mappingResult))success + failure:(void (^)(RKObjectRequestOperation *operation, NSError *error))failure; + +///------------------------------------------------ +/// @name Managing Request and Response Descriptors +///------------------------------------------------ + +/** + Returns an array containing the `RKRequestDescriptor` objects added to the manager. + + @return An array containing the request descriptors of the receiver. The elements of the array are instances of `RKRequestDescriptor`. + + @see RKRequestDescriptor + */ +@property (nonatomic, readonly) NSArray *requestDescriptors; + +/** + Adds a request descriptor to the manager. + + @param requestDescriptor The request descriptor object to the be added to the manager. + */ +- (void)addRequestDescriptor:(RKRequestDescriptor *)requestDescriptor; + +/** + Adds the `RKRequestDescriptor` objects contained in a given array to the manager. + + @param requestDescriptors An array of `RKRequestDescriptor` objects to be added to the manager. + @exception NSInvalidArgumentException Raised if any element of the given array is not an `RKRequestDescriptor` object. + */ +- (void)addRequestDescriptorsFromArray:(NSArray *)requestDescriptors; + +/** + Removes a given request descriptor from the manager. + + @param requestDescriptor An `RKRequestDescriptor` object to be removed from the manager. + */ +- (void)removeRequestDescriptor:(RKRequestDescriptor *)requestDescriptor; + +/** + Returns an array containing the `RKResponseDescriptor` objects added to the manager. + + @return An array containing the request descriptors of the receiver. The elements of the array are instances of `RKRequestDescriptor`. + + @see RKResponseDescriptor + */ +@property (nonatomic, readonly) NSArray *responseDescriptors; + +/** + Adds a response descriptor to the manager. + + Adding a response descriptor to the manager sets the `baseURL` of the descriptor to the `baseURL` of the manager, causing it to evaluate URL objects relatively. + + @param responseDescriptor The response descriptor object to the be added to the manager. + */ +- (void)addResponseDescriptor:(RKResponseDescriptor *)responseDescriptor; + +/** + Adds the `RKResponseDescriptor` objects contained in a given array to the manager. + + @param responseDescriptors An array of `RKResponseDescriptor` objects to be added to the manager. + @exception NSInvalidArgumentException Raised if any element of the given array is not an `RKResponseDescriptor` object. + */ +- (void)addResponseDescriptorsFromArray:(NSArray *)responseDescriptors; + +/** + Removes a given response descriptor from the manager. + + @param responseDescriptor An `RKResponseDescriptor` object to be removed from the manager. + */ +- (void)removeResponseDescriptor:(RKResponseDescriptor *)responseDescriptor; + +///---------------------------------------- +/// @name Configuring Core Data Integration +///---------------------------------------- + +#ifdef RKCoreDataIncluded +/** + A Core Data backed object store for persisting objects that have been fetched from the Web + */ +@property (nonatomic, strong) RKManagedObjectStore *managedObjectStore; + +/** + An array of `RKFetchRequestBlock` blocks used to map `NSURL` objects into corresponding `NSFetchRequest` objects. + + When searched, the blocks are iterated in the reverse-order of their registration and the first block with a non-nil return value halts the search. + */ +@property (nonatomic, readonly) NSArray *fetchRequestBlocks; + +/** + Adds the given `RKFetchRequestBlock` block to the manager. + + @param block A block object to be executed when constructing an `NSFetchRequest` object from a given `NSURL`. The block has a return type of `NSFetchRequest` and accepts a single `NSURL` argument. + */ +- (void)addFetchRequestBlock:(NSFetchRequest *(^)(NSURL *URL))block; +#endif + +///------------------------------------ +/// @name Accessing Paginated Resources +///------------------------------------ + +/** + The object mapping describing how to map pagination metadata from paginated responses. + + The object mapping must have an object class of `RKPaginator`. + + @see [RKPaginator initWithRequest:paginationMapping:responseDescriptors] + */ +@property (nonatomic, strong) RKObjectMapping *paginationMapping; + +/** + Creates and returns a paginator object configured to paginate the collection resource accessible at the specified path pattern. + + The paginator instantiated will be initialized with a URL built by appending the given pathPattern to the baseURL of the client. The response descriptors and Core Data configuration, if any, are inherited from the receiver. + + @param pathPattern A patterned URL fragment to be appended to the baseURL of the receiver in order to construct the pattern URL with which to access the paginated collection. + @return The newly created paginator instance. + @see RKPaginator + @warning Will raise an exception if the value of the `paginationMapping` property is nil. + */ +- (RKPaginator *)paginatorWithPathPattern:(NSString *)pathPattern; + +/** + Creates and returns a paginator object configured to paginate the collection resource accessible at the specified path pattern and the given parameters. + + The paginator instantiated will be initialized with a URL built by appending the given pathPattern to the baseURL of the client and the given parameters if any. The response descriptors and Core Data configuration, if any, are inherited from the receiver. + + @param pathPattern A patterned URL fragment to be appended to the baseURL of the receiver in order to construct the pattern URL with which to access the paginated collection. + @param parameters The parameters to be encoded and appended as the query string for the request URL. May be nil. + @return The newly created paginator instance. + @see RKPaginator + @warning Will raise an exception if the value of the `paginationMapping` property is nil. + */ +- (RKPaginator *)paginatorWithPathPattern:(NSString *)pathPattern parameters:(NSDictionary *)parameters; + +@end + +#ifdef _SYSTEMCONFIGURATION_H +/** + Returns a string description of the given network status. + + @param networkReachabilityStatus The network reachability status. + @return A string describing the reachability status. + */ +NSString *RKStringFromNetworkReachabilityStatus(AFNetworkReachabilityStatus networkReachabilityStatus); +#endif diff --git a/Pods/RestKit/Code/Network/RKObjectManager.m b/Pods/RestKit/Code/Network/RKObjectManager.m new file mode 100644 index 0000000..2d27428 --- /dev/null +++ b/Pods/RestKit/Code/Network/RKObjectManager.m @@ -0,0 +1,1018 @@ +// +// RKObjectManager.m +// RestKit +// +// Created by Jeremy Ellison on 8/14/09. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import <objc/runtime.h> +#import "RKObjectManager.h" +#import "RKObjectParameterization.h" +#import "RKRequestDescriptor.h" +#import "RKResponseDescriptor.h" +#import "RKDictionaryUtilities.h" +#import "RKMIMETypes.h" +#import "RKLog.h" +#import "RKMIMETypeSerialization.h" +#import "RKPathMatcher.h" +#import "RKMappingErrors.h" +#import "RKPaginator.h" +#import "RKDynamicMapping.h" +#import "RKRelationshipMapping.h" +#import "RKObjectRequestOperation.h" +#import "RKRouter.h" +#import "RKRoute.h" +#import "RKRouteSet.h" + +#ifdef _COREDATADEFINES_H +# if __has_include("RKCoreData.h") +# define RKCoreDataIncluded +# import "RKManagedObjectStore.h" +# import "RKManagedObjectRequestOperation.h" +# endif +#endif + +#if !__has_feature(objc_arc) +#error RestKit must be built with ARC. \ +You can turn on ARC for only RestKit files by adding "-fobjc-arc" to the build phase for each of its files. +#endif + +////////////////////////////////// +// Shared Instance + +static RKObjectManager *sharedManager = nil; + +////////////////////////////////// +// Utility Functions + +/** + Returns the subset of the given array of `RKResponseDescriptor` objects that match the given path. + + @param responseDescriptors An array of `RKResponseDescriptor` objects. + @param path The path for which to select matching response descriptors. + @param method The method for which to select matching response descriptors. + @return An `NSArray` object whose elements are `RKResponseDescriptor` objects matching the given path and method. + */ +#ifdef RKCoreDataIncluded +static NSArray *RKFilteredArrayOfResponseDescriptorsMatchingPathAndMethod(NSArray *responseDescriptors, NSString *path, RKRequestMethod method) +{ + NSIndexSet *indexSet = [responseDescriptors indexesOfObjectsPassingTest:^BOOL(RKResponseDescriptor *responseDescriptor, NSUInteger idx, BOOL *stop) { + return [responseDescriptor matchesPath:path] && (method & responseDescriptor.method); + }]; + return [responseDescriptors objectsAtIndexes:indexSet]; +} +#endif + +/** + Returns the first `RKRequestDescriptor` object from the given array that matches the given object. + + @param requestDescriptors An array of `RKRequestDescriptor` objects. + @param object The object to find a matching request descriptor for. + @return An `RKRequestDescriptor` object matching the given object, or `nil` if none could be found. + */ +RKRequestDescriptor *RKRequestDescriptorFromArrayMatchingObjectAndRequestMethod(NSArray *requestDescriptors, id object, RKRequestMethod requestMethod); +RKRequestDescriptor *RKRequestDescriptorFromArrayMatchingObjectAndRequestMethod(NSArray *requestDescriptors, id object, RKRequestMethod requestMethod) +{ + Class searchClass = [object class]; + do { + for (RKRequestDescriptor *requestDescriptor in requestDescriptors) { + if ([requestDescriptor.objectClass isEqual:searchClass] && (requestMethod == requestDescriptor.method)) return requestDescriptor; + } + + for (RKRequestDescriptor *requestDescriptor in requestDescriptors) { + if ([requestDescriptor.objectClass isEqual:searchClass] && (requestMethod & requestDescriptor.method)) return requestDescriptor; + } + searchClass = [searchClass superclass]; + } while (searchClass); + + return nil; +} + +extern NSString *RKStringDescribingRequestMethod(RKRequestMethod method); + +@interface RKObjectParameters : NSObject + +@property (nonatomic, strong) NSMutableDictionary *parameters; +- (void)addParameters:(NSDictionary *)serialization atRootKeyPath:(NSString *)rootKeyPath inArray:(BOOL)inArray; + +@end + +@implementation RKObjectParameters + +- (instancetype)init +{ + self = [super init]; + if (self) { + self.parameters = [NSMutableDictionary new]; + } + return self; +} + +- (void)addParameters:(NSDictionary *)parameters atRootKeyPath:(NSString *)rootKeyPath inArray:(BOOL)inArray +{ + id rootKey = rootKeyPath ?: [NSNull null]; + id nonNestedParameters = rootKeyPath ? parameters[rootKeyPath] : parameters; + id value = (self.parameters)[rootKey]; + if (value) { + if ([value isKindOfClass:[NSMutableArray class]]) { + [value addObject:nonNestedParameters]; + } else if ([value isKindOfClass:[NSDictionary class]]) { + NSMutableArray *mutableArray = [NSMutableArray arrayWithObjects:value, nonNestedParameters, nil]; + (self.parameters)[rootKey] = mutableArray; + } else { + [NSException raise:NSInvalidArgumentException format:@"Unexpected argument of type '%@': expected an NSDictionary or NSArray.", [value class]]; + } + } else { + (self.parameters)[rootKey] = (inArray ? @[ nonNestedParameters ] : nonNestedParameters); + } +} + +- (id)requestParameters +{ + if ([self.parameters count] == 0) return nil; + id valueAtNullKey = (self.parameters)[[NSNull null]]; + if (valueAtNullKey) { + if ([self.parameters count] == 1) return valueAtNullKey; + + // If we have values at `[NSNull null]` and other key paths, we have an invalid configuration + [NSException raise:NSInvalidArgumentException format:@"Invalid request descriptor configuration: The request descriptors specify that multiple objects be serialized at incompatible key paths. Cannot serialize objects at the `nil` root key path in the same request as objects with a non-nil root key path. Please check your request descriptors and try again."]; + } + return self.parameters; +} + +@end + +/** + Visits all mappings accessible via relationships or dynamic mapping in an object graph starting from a given mapping. + */ +@interface RKMappingGraphVisitor : NSObject + +@property (nonatomic, readonly) NSSet *mappings; + +- (instancetype)initWithMapping:(RKMapping *)mapping NS_DESIGNATED_INITIALIZER; + +@end + +@interface RKMappingGraphVisitor () +@property (nonatomic, readwrite) NSMutableSet *mutableMappings; +@end + +@implementation RKMappingGraphVisitor + +- (instancetype)initWithMapping:(RKMapping *)mapping +{ + self = [super init]; + if (self) { + self.mutableMappings = [NSMutableSet set]; + [self visitMapping:mapping]; + } + return self; +} + +- (NSSet *)mappings +{ + return self.mutableMappings; +} + +- (void)visitMapping:(RKMapping *)mapping +{ + if ([self.mappings containsObject:mapping]) return; + [self.mutableMappings addObject:mapping]; + + if ([mapping isKindOfClass:[RKDynamicMapping class]]) { + RKDynamicMapping *dynamicMapping = (RKDynamicMapping *)mapping; + for (RKMapping *nestedMapping in dynamicMapping.objectMappings) { + [self visitMapping:nestedMapping]; + } + } else if ([mapping isKindOfClass:[RKObjectMapping class]]) { + RKObjectMapping *objectMapping = (RKObjectMapping *)mapping; + for (RKRelationshipMapping *relationshipMapping in objectMapping.relationshipMappings) { + [self visitMapping:relationshipMapping.mapping]; + } + } +} + +@end + +/** + Returns `YES` if the given array of `RKResponseDescriptor` objects contains an `RKEntityMapping` anywhere in its object graph. + + @param responseDescriptors An array of `RKResponseDescriptor` objects. + @return `YES` if the `mapping` property of any of the response descriptor objects in the given array is an instance of `RKEntityMapping`, else `NO`. + */ +#ifdef RKCoreDataIncluded +static BOOL RKDoesArrayOfResponseDescriptorsContainEntityMapping(NSArray *responseDescriptors) +{ + // Visit all mappings accessible from the object graphs of all response descriptors + NSMutableSet *accessibleMappings = [NSMutableSet set]; + for (RKResponseDescriptor *responseDescriptor in responseDescriptors) { + if (! [accessibleMappings containsObject:responseDescriptor.mapping]) { + RKMappingGraphVisitor *graphVisitor = [[RKMappingGraphVisitor alloc] initWithMapping:responseDescriptor.mapping]; + [accessibleMappings unionSet:graphVisitor.mappings]; + } + } + + // Enumerate all mappings and search for an `RKEntityMapping` + for (RKMapping *mapping in accessibleMappings) { + if ([mapping isKindOfClass:[RKEntityMapping class]]) { + return YES; + } + + if ([mapping isKindOfClass:[RKDynamicMapping class]]) { + RKDynamicMapping *dynamicMapping = (RKDynamicMapping *)mapping; + if ([dynamicMapping.objectMappings count] == 0) { + // Likely means that there is a representation block, assume `YES` + return YES; + } + } + } + + return NO; +} +#endif + +BOOL RKDoesArrayOfResponseDescriptorsContainOnlyEntityMappings(NSArray *responseDescriptors); +BOOL RKDoesArrayOfResponseDescriptorsContainOnlyEntityMappings(NSArray *responseDescriptors) +{ +#ifdef RKCoreDataIncluded + // Visit all mappings accessible from the object graphs of all response descriptors + NSMutableSet *accessibleMappings = [NSMutableSet set]; + for (RKResponseDescriptor *responseDescriptor in responseDescriptors) { + if (! [accessibleMappings containsObject:responseDescriptor.mapping]) { + RKMappingGraphVisitor *graphVisitor = [[RKMappingGraphVisitor alloc] initWithMapping:responseDescriptor.mapping]; + [accessibleMappings unionSet:graphVisitor.mappings]; + } + } + + NSMutableSet *mappingClasses = [NSMutableSet set]; + // Enumerate all mappings and search for an `RKEntityMapping` + for (RKMapping *mapping in accessibleMappings) { + if ([mapping isKindOfClass:[RKDynamicMapping class]]) { + [mappingClasses addObjectsFromArray:[[(RKDynamicMapping *)mapping objectMappings] valueForKey:@"class"]]; + } else { + [mappingClasses addObject:mapping.class]; + } + } + + if ([mappingClasses count]) { + for (Class mappingClass in mappingClasses) { + if (! [mappingClass isSubclassOfClass:[RKEntityMapping class]]) { + return NO; + } + } + return YES; + } +#endif + + return NO; +} + +static BOOL RKDoesArrayOfResponseDescriptorsContainMappingForClass(NSArray *responseDescriptors, Class classToBeMapped) +{ + // Visit all mappings accessible from the object graphs of all response descriptors + NSMutableSet *accessibleMappings = [NSMutableSet set]; + for (RKResponseDescriptor *responseDescriptor in responseDescriptors) { + if (! [accessibleMappings containsObject:responseDescriptor.mapping]) { + RKMappingGraphVisitor *graphVisitor = [[RKMappingGraphVisitor alloc] initWithMapping:responseDescriptor.mapping]; + [accessibleMappings unionSet:graphVisitor.mappings]; + } + } + + // Enumerate all mappings and search for a mapping matching the class + for (RKMapping *mapping in accessibleMappings) { + if ([mapping isKindOfClass:[RKObjectMapping class]]) { + if ([[(RKObjectMapping *)mapping objectClass] isSubclassOfClass:classToBeMapped]) return YES; + } + + if ([mapping isKindOfClass:[RKDynamicMapping class]]) { + RKDynamicMapping *dynamicMapping = (RKDynamicMapping *)mapping; + for (RKObjectMapping *mapping in dynamicMapping.objectMappings) { + if ([[(RKObjectMapping *)mapping objectClass] isSubclassOfClass:classToBeMapped]) return YES; + } + } + } + + return NO; +} + +static NSString *RKMIMETypeFromAFHTTPClientParameterEncoding(AFHTTPClientParameterEncoding encoding) +{ + switch (encoding) { + case AFFormURLParameterEncoding: + return RKMIMETypeFormURLEncoded; + break; + + case AFJSONParameterEncoding: + return RKMIMETypeJSON; + break; + + case AFPropertyListParameterEncoding: + break; + + default: + RKLogWarning(@"RestKit is unable to infer the appropriate request serialization MIME Type from an `AFHTTPClientParameterEncoding` value of %d: defaulting to `RKMIMETypeFormURLEncoded`", encoding); + break; + } + + return RKMIMETypeFormURLEncoded; +} + +@interface AFHTTPClient () +@property (readonly, nonatomic, strong) NSURLCredential *defaultCredential; +@end + +/////////////////////////////////// + +@interface RKObjectManager () +@property (nonatomic, strong) NSMutableArray *mutableRequestDescriptors; +@property (nonatomic, strong) NSMutableArray *mutableResponseDescriptors; +@property (nonatomic, strong) NSMutableArray *mutableFetchRequestBlocks; +@property (nonatomic, strong) NSMutableArray *registeredHTTPRequestOperationClasses; +@property (nonatomic, strong) NSMutableArray *registeredObjectRequestOperationClasses; +@property (nonatomic, strong) NSMutableArray *registeredManagedObjectRequestOperationClasses; + +@end + +@implementation RKObjectManager + +- (instancetype)initWithHTTPClient:(AFHTTPClient *)client +{ + self = [super init]; + if (self) { + self.HTTPClient = client; + self.router = [[RKRouter alloc] initWithBaseURL:client.baseURL]; + self.operationQueue = [NSOperationQueue new]; + self.mutableRequestDescriptors = [NSMutableArray new]; + self.mutableResponseDescriptors = [NSMutableArray new]; + self.mutableFetchRequestBlocks = [NSMutableArray new]; + self.registeredHTTPRequestOperationClasses = [NSMutableArray new]; + self.registeredManagedObjectRequestOperationClasses = [NSMutableArray new]; + self.registeredObjectRequestOperationClasses = [NSMutableArray new]; + self.requestSerializationMIMEType = RKMIMETypeFromAFHTTPClientParameterEncoding(client.parameterEncoding); + + // Set shared manager if nil + if (nil == sharedManager) { + [RKObjectManager setSharedManager:self]; + } + } + + return self; +} + ++ (instancetype)sharedManager +{ + return sharedManager; +} + ++ (void)setSharedManager:(RKObjectManager *)manager +{ + sharedManager = manager; +} + ++ (RKObjectManager *)managerWithBaseURL:(NSURL *)baseURL +{ + RKObjectManager *manager = [[self alloc] initWithHTTPClient:[AFHTTPClient clientWithBaseURL:baseURL]]; + [manager.HTTPClient registerHTTPOperationClass:[AFJSONRequestOperation class]]; + [manager setAcceptHeaderWithMIMEType:RKMIMETypeJSON]; + manager.requestSerializationMIMEType = RKMIMETypeFormURLEncoded; + return manager; +} + +- (void)setAcceptHeaderWithMIMEType:(NSString *)MIMEType; +{ + [self.HTTPClient setDefaultHeader:@"Accept" value:MIMEType]; +} + +- (NSURL *)baseURL +{ + return self.HTTPClient.baseURL; +} + +- (NSDictionary *)defaultHeaders +{ + return self.HTTPClient.defaultHeaders; +} + +#pragma mark - Building Requests + +/** + This method is the `RKObjectManager` analog for the method of the same name on `AFHTTPClient`. + */ +- (NSMutableURLRequest *)requestWithMethod:(NSString *)method + path:(NSString *)path + parameters:(NSDictionary *)parameters +{ + NSMutableURLRequest* request; + if (parameters && !([method isEqualToString:@"GET"] || [method isEqualToString:@"HEAD"] || [method isEqualToString:@"DELETE"])) { + // NOTE: If the HTTP client has been subclasses, then the developer may be trying to perform signing on the request + NSDictionary *parametersForClient = [self.HTTPClient isMemberOfClass:[AFHTTPClient class]] ? nil : parameters; + request = [self.HTTPClient requestWithMethod:method path:path parameters:parametersForClient]; + + NSError *error = nil; + NSString *charset = (__bridge NSString *)CFStringConvertEncodingToIANACharSetName(CFStringConvertNSStringEncodingToEncoding(self.HTTPClient.stringEncoding)); + [request setValue:[NSString stringWithFormat:@"%@; charset=%@", self.requestSerializationMIMEType, charset] forHTTPHeaderField:@"Content-Type"]; + NSData *requestBody = [RKMIMETypeSerialization dataFromObject:parameters MIMEType:self.requestSerializationMIMEType error:&error]; + [request setHTTPBody:requestBody]; + } else { + request = [self.HTTPClient requestWithMethod:method path:path parameters:parameters]; + } + + return request; +} + +- (NSMutableURLRequest *)requestWithPathForRouteNamed:(NSString *)routeName + object:(id)object + parameters:(NSDictionary *)parameters +{ + RKRequestMethod method; + NSURL *URL = [self.router URLForRouteNamed:routeName method:&method object:object]; + NSAssert(URL, @"No route found named '%@'", routeName); + return [self requestWithMethod:RKStringFromRequestMethod(method) path:[URL relativeString] parameters:parameters]; +} + +- (NSMutableURLRequest *)requestWithPathForRelationship:(NSString *)relationship + ofObject:(id)object + method:(RKRequestMethod)method + parameters:(NSDictionary *)parameters +{ + NSURL *URL = [self.router URLForRelationship:relationship ofObject:object method:method]; + NSAssert(URL, @"No relationship route found for the '%@' class with the name '%@'", NSStringFromClass([object class]), relationship); + return [self requestWithMethod:RKStringFromRequestMethod(method) path:[URL relativeString] parameters:parameters]; +} + +- (id)mergedParametersWithObject:(id)object method:(RKRequestMethod)method parameters:(NSDictionary *)parameters +{ + NSArray *objectsToParameterize = ([object isKindOfClass:[NSArray class]] || object == nil) ? object : @[ object ]; + RKObjectParameters *objectParameters = [RKObjectParameters new]; + for (id objectToParameterize in objectsToParameterize) { + RKRequestDescriptor *requestDescriptor = RKRequestDescriptorFromArrayMatchingObjectAndRequestMethod(self.requestDescriptors, objectToParameterize, method); + if ((method != RKRequestMethodGET && method != RKRequestMethodDELETE) && requestDescriptor) { + NSError *error = nil; + NSDictionary *parametersForObject = [RKObjectParameterization parametersWithObject:objectToParameterize requestDescriptor:requestDescriptor error:&error]; + if (error) { + RKLogError(@"Object parameterization failed while building %@ request for object '%@': %@", RKStringFromRequestMethod(method), objectToParameterize, error); + return nil; + } + // Ensure that a single object inputted as an array is emitted as an array when serialized + BOOL inArray = ([object isKindOfClass:[NSArray class]] && [object count] == 1); + [objectParameters addParameters:parametersForObject atRootKeyPath:requestDescriptor.rootKeyPath inArray:inArray]; + } + } + id requestParameters = [objectParameters requestParameters]; + + // Merge the extra parameters if possible + if ([requestParameters isKindOfClass:[NSArray class]] && parameters) { + [NSException raise:NSInvalidArgumentException format:@"Cannot merge parameters with array of object representations serialized with a nil root key path."]; + } else if (requestParameters && parameters) { + requestParameters = RKDictionaryByMergingDictionaryWithDictionary(requestParameters, parameters); + } else if (parameters && !requestParameters) { + requestParameters = parameters; + } + + return requestParameters; +} + +- (NSMutableURLRequest *)requestWithObject:(id)object + method:(RKRequestMethod)method + path:(NSString *)path + parameters:(NSDictionary *)parameters; +{ + NSString *requestPath = (path) ? path : [[self.router URLForObject:object method:method] relativeString]; + id requestParameters = [self mergedParametersWithObject:object method:method parameters:parameters]; + return [self requestWithMethod:RKStringFromRequestMethod(method) path:requestPath parameters:requestParameters]; +} + +- (NSMutableURLRequest *)multipartFormRequestWithObject:(id)object + method:(RKRequestMethod)method + path:(NSString *)path + parameters:(NSDictionary *)parameters + constructingBodyWithBlock:(void (^)(id <AFMultipartFormData> formData))block +{ + NSString *requestPath = (path) ? path : [[self.router URLForObject:object method:method] relativeString]; + id requestParameters = [self mergedParametersWithObject:object method:method parameters:parameters]; + NSMutableURLRequest *multipartRequest = [self.HTTPClient multipartFormRequestWithMethod:RKStringFromRequestMethod(method) + path:requestPath + parameters:requestParameters + constructingBodyWithBlock:block]; + return multipartRequest; +} + +#pragma mark - Registering Subclasses + +- (BOOL)registerRequestOperationClass:(Class)operationClass +{ + Class managedObjectRequestOperationClass = NSClassFromString(@"RKManagedObjectRequestOperation"); + if (managedObjectRequestOperationClass && [operationClass isSubclassOfClass:managedObjectRequestOperationClass]) { + [self.registeredManagedObjectRequestOperationClasses removeObject:operationClass]; + [self.registeredManagedObjectRequestOperationClasses insertObject:operationClass atIndex:0]; + return YES; + } else if ([operationClass isSubclassOfClass:[RKObjectRequestOperation class]]) { + [self.registeredObjectRequestOperationClasses removeObject:operationClass]; + [self.registeredObjectRequestOperationClasses insertObject:operationClass atIndex:0]; + return YES; + } else if ([operationClass isSubclassOfClass:[RKHTTPRequestOperation class]]) { + [self.registeredHTTPRequestOperationClasses removeObject:operationClass]; + [self.registeredHTTPRequestOperationClasses insertObject:operationClass atIndex:0]; + return YES; + } + + return NO; +} + +- (void)unregisterRequestOperationClass:(Class)operationClass +{ + [self.registeredHTTPRequestOperationClasses removeObject:operationClass]; + [self.registeredObjectRequestOperationClasses removeObject:operationClass]; + [self.registeredManagedObjectRequestOperationClasses removeObject:operationClass]; +} + +- (Class)requestOperationClassForRequest:(NSURLRequest *)request fromRegisteredClasses:(NSArray *)registeredClasses +{ + Class requestOperationClass = nil; + NSEnumerator *enumerator = [registeredClasses reverseObjectEnumerator]; + while (requestOperationClass = [enumerator nextObject]) { + if ([requestOperationClass canProcessRequest:request]) break; + requestOperationClass = nil; + } + return requestOperationClass; +} + +#pragma mark - Object Request Operations + +- (void)copyStateFromHTTPClientToHTTPRequestOperation:(AFHTTPRequestOperation *)operation +{ + operation.credential = self.HTTPClient.defaultCredential; + operation.allowsInvalidSSLCertificate = self.HTTPClient.allowsInvalidSSLCertificate; +#ifdef _AFNETWORKING_PIN_SSL_CERTIFICATES_ + operation.SSLPinningMode = self.HTTPClient.defaultSSLPinningMode; +#endif +} + +- (RKObjectRequestOperation *)objectRequestOperationWithRequest:(NSURLRequest *)request + success:(void (^)(RKObjectRequestOperation *operation, RKMappingResult *mappingResult))success + failure:(void (^)(RKObjectRequestOperation *operation, NSError *error))failure +{ + return [self objectRequestOperationWithRequest:request responseDescriptors:self.responseDescriptors success:success failure:failure]; +} + +- (RKObjectRequestOperation *)objectRequestOperationWithRequest:(NSURLRequest *)request + responseDescriptors:(NSArray *)responseDescriptors + success:(void (^)(RKObjectRequestOperation *operation, RKMappingResult *mappingResult))success + failure:(void (^)(RKObjectRequestOperation *operation, NSError *error))failure +{ + Class HTTPRequestOperationClass = [self requestOperationClassForRequest:request fromRegisteredClasses:self.registeredHTTPRequestOperationClasses] ?: [RKHTTPRequestOperation class]; + RKHTTPRequestOperation *HTTPRequestOperation = [[HTTPRequestOperationClass alloc] initWithRequest:request]; + [self copyStateFromHTTPClientToHTTPRequestOperation:HTTPRequestOperation]; + Class objectRequestOperationClass = [self requestOperationClassForRequest:request fromRegisteredClasses:self.registeredObjectRequestOperationClasses] ?: [RKObjectRequestOperation class]; + RKObjectRequestOperation *operation = [[objectRequestOperationClass alloc] initWithHTTPRequestOperation:HTTPRequestOperation responseDescriptors:responseDescriptors]; + [operation setCompletionBlockWithSuccess:success failure:failure]; + return operation; +} + +#ifdef RKCoreDataIncluded +- (RKManagedObjectRequestOperation *)managedObjectRequestOperationWithRequest:(NSURLRequest *)request + managedObjectContext:(NSManagedObjectContext *)managedObjectContext + success:(void (^)(RKObjectRequestOperation *operation, RKMappingResult *mappingResult))success + failure:(void (^)(RKObjectRequestOperation *operation, NSError *error))failure +{ + return [self managedObjectRequestOperationWithRequest:request responseDescriptors:self.responseDescriptors managedObjectContext:managedObjectContext success:success failure:failure]; +} + +- (RKManagedObjectRequestOperation *)managedObjectRequestOperationWithRequest:(NSURLRequest *)request + responseDescriptors:(NSArray *)responseDescriptors + managedObjectContext:(NSManagedObjectContext *)managedObjectContext + success:(void (^)(RKObjectRequestOperation *operation, RKMappingResult *mappingResult))success + failure:(void (^)(RKObjectRequestOperation *operation, NSError *error))failure +{ + Class HTTPRequestOperationClass = [self requestOperationClassForRequest:request fromRegisteredClasses:self.registeredHTTPRequestOperationClasses] ?: [RKHTTPRequestOperation class]; + RKHTTPRequestOperation *HTTPRequestOperation = [[HTTPRequestOperationClass alloc] initWithRequest:request]; + [self copyStateFromHTTPClientToHTTPRequestOperation:HTTPRequestOperation]; + Class objectRequestOperationClass = [self requestOperationClassForRequest:request fromRegisteredClasses:self.registeredManagedObjectRequestOperationClasses] ?: [RKManagedObjectRequestOperation class]; + RKManagedObjectRequestOperation *operation = (RKManagedObjectRequestOperation *)[[objectRequestOperationClass alloc] initWithHTTPRequestOperation:HTTPRequestOperation responseDescriptors:responseDescriptors]; + [operation setCompletionBlockWithSuccess:success failure:failure]; + operation.managedObjectContext = managedObjectContext ?: self.managedObjectStore.mainQueueManagedObjectContext; + operation.managedObjectCache = self.managedObjectStore.managedObjectCache; + operation.fetchRequestBlocks = self.fetchRequestBlocks; + return operation; +} +#endif + +- (id)appropriateObjectRequestOperationWithObject:(id)object + method:(RKRequestMethod)method + path:(NSString *)path + parameters:(NSDictionary *)parameters +{ + RKObjectRequestOperation *operation = nil; + NSURLRequest *request = [self requestWithObject:object method:method path:path parameters:parameters]; + NSDictionary *routingMetadata = nil; + if (! path) { + RKRoute *route = [self.router.routeSet routeForObject:object method:method]; + NSDictionary *interpolatedParameters = nil; + NSURL *URL = [self URLWithRoute:route object:object interpolatedParameters:&interpolatedParameters]; + if (! URL) { + RKLogError(@"Failed to construct a URL from the provided object. Returning nil."); + return operation; + } + path = [URL relativeString]; + + routingMetadata = @{ @"routing": @{ @"parameters": interpolatedParameters, @"route": route }, + @"query": @{ @"parameters": parameters ?: @{} } }; + } else if (parameters) { + routingMetadata = @{ @"query": @{ @"parameters": parameters } }; + } + +#ifdef RKCoreDataIncluded + NSArray *matchingDescriptors = RKFilteredArrayOfResponseDescriptorsMatchingPathAndMethod(self.responseDescriptors, path, method); + BOOL containsEntityMapping = RKDoesArrayOfResponseDescriptorsContainEntityMapping(matchingDescriptors); + BOOL isManagedObjectRequestOperation = (containsEntityMapping || [object isKindOfClass:[NSManagedObject class]]); + + if (isManagedObjectRequestOperation && !self.managedObjectStore) RKLogWarning(@"Asked to create an `RKManagedObjectRequestOperation` object, but managedObjectStore is nil."); + if (isManagedObjectRequestOperation && self.managedObjectStore) { + // Construct a Core Data operation + NSManagedObjectContext *managedObjectContext = [object respondsToSelector:@selector(managedObjectContext)] ? [object managedObjectContext] : self.managedObjectStore.mainQueueManagedObjectContext; + operation = [self managedObjectRequestOperationWithRequest:request responseDescriptors:matchingDescriptors managedObjectContext:managedObjectContext success:nil failure:nil]; + + if ([object isKindOfClass:[NSManagedObject class]]) { + static NSPredicate *temporaryObjectsPredicate = nil; + if (! temporaryObjectsPredicate) temporaryObjectsPredicate = [NSPredicate predicateWithFormat:@"objectID.isTemporaryID == YES"]; + NSSet *temporaryObjects = [[managedObjectContext insertedObjects] filteredSetUsingPredicate:temporaryObjectsPredicate]; + if ([temporaryObjects count]) { + RKLogInfo(@"Asked to perform object request for NSManagedObject with temporary object IDs: Obtaining permanent ID before proceeding."); + __block BOOL _blockSuccess; + __block NSError *_blockError; + + [[object managedObjectContext] performBlockAndWait:^{ + _blockSuccess = [[object managedObjectContext] obtainPermanentIDsForObjects:[temporaryObjects allObjects] error:&_blockError]; + }]; + if (! _blockSuccess) RKLogWarning(@"Failed to obtain permanent ID for object %@: %@", object, _blockError); + } + } + } else { + // Non-Core Data operation + operation = [self objectRequestOperationWithRequest:request responseDescriptors:matchingDescriptors success:nil failure:nil]; + } +#else + // Non-Core Data operation + operation = [self objectRequestOperationWithRequest:request success:nil failure:nil]; +#endif + + if (RKDoesArrayOfResponseDescriptorsContainMappingForClass(self.responseDescriptors, [object class])) operation.targetObject = object; + operation.mappingMetadata = routingMetadata; + return operation; +} + +- (NSURL *)URLWithRoute:(RKRoute *)route object:(id)object interpolatedParameters:(NSDictionary **)interpolatedParameters +{ + NSString *path = nil; + if (object) { + RKPathMatcher *pathMatcher = [RKPathMatcher pathMatcherWithPattern:route.pathPattern]; + path = [pathMatcher pathFromObject:object addingEscapes:route.shouldEscapePath interpolatedParameters:interpolatedParameters]; + } else { + // When there is no object, the path pattern is our complete path + path = route.pathPattern; + if (interpolatedParameters) *interpolatedParameters = @{}; + } + return [NSURL URLWithString:path relativeToURL:self.baseURL]; +} + +- (void)getObjectsAtPathForRelationship:(NSString *)relationshipName + ofObject:(id)object + parameters:(NSDictionary *)parameters + success:(void (^)(RKObjectRequestOperation *operation, RKMappingResult *mappingResult))success + failure:(void (^)(RKObjectRequestOperation *operation, NSError *error))failure +{ + RKRoute *route = [self.router.routeSet routeForRelationship:relationshipName ofClass:[object class] method:RKRequestMethodGET]; + NSDictionary *interpolatedParameters = nil; + NSURL *URL = [self URLWithRoute:route object:object interpolatedParameters:&interpolatedParameters]; + NSAssert(URL, @"Failed to generate URL for relationship named '%@' for object: %@", relationshipName, object); + RKObjectRequestOperation *operation = [self appropriateObjectRequestOperationWithObject:nil method:RKRequestMethodGET path:[URL relativeString] parameters:parameters]; + + operation.mappingMetadata = @{ @"routing": @{ @"parameters": interpolatedParameters, @"route": route }, + @"query": @{ @"parameters": parameters ?: @{} } }; + + [operation setCompletionBlockWithSuccess:success failure:failure]; + [self enqueueObjectRequestOperation:operation]; +} + +- (void)getObjectsAtPathForRouteNamed:(NSString *)routeName + object:(id)object + parameters:(NSDictionary *)parameters + success:(void (^)(RKObjectRequestOperation *operation, RKMappingResult *mappingResult))success + failure:(void (^)(RKObjectRequestOperation *operation, NSError *error))failure +{ + NSParameterAssert(routeName); + RKRoute *route = [self.router.routeSet routeForName:routeName]; + NSDictionary *interpolatedParameters = nil; + NSURL *URL = [self URLWithRoute:route object:object interpolatedParameters:&interpolatedParameters]; + NSAssert(URL, @"No route found named '%@'", routeName); + NSAssert(route.method & RKRequestMethodGET, @"Expected route named '%@' to specify a GET, but it does not", routeName); + + RKObjectRequestOperation *operation = [self appropriateObjectRequestOperationWithObject:nil method:RKRequestMethodGET path:[URL relativeString] parameters:parameters]; + + operation.mappingMetadata = @{ @"routing": @{ @"parameters": interpolatedParameters, @"route": route }, + @"query": @{ @"parameters": parameters ?: @{} } }; + + [operation setCompletionBlockWithSuccess:success failure:failure]; + [self enqueueObjectRequestOperation:operation]; +} + +- (void)getObjectsAtPath:(NSString *)path + parameters:(NSDictionary *)parameters + success:(void (^)(RKObjectRequestOperation *operation, RKMappingResult *mappingResult))success + failure:(void (^)(RKObjectRequestOperation *operation, NSError *error))failure +{ + NSParameterAssert(path); + RKObjectRequestOperation *operation = [self appropriateObjectRequestOperationWithObject:nil method:RKRequestMethodGET path:path parameters:parameters]; + [operation setCompletionBlockWithSuccess:success failure:failure]; + [self enqueueObjectRequestOperation:operation]; +} + +- (void)getObject:(id)object + path:(NSString *)path + parameters:(NSDictionary *)parameters + success:(void (^)(RKObjectRequestOperation *operation, RKMappingResult *mappingResult))success + failure:(void (^)(RKObjectRequestOperation *operation, NSError *error))failure +{ + NSAssert(object || path, @"Cannot make a request without an object or a path."); + RKObjectRequestOperation *operation = [self appropriateObjectRequestOperationWithObject:object method:RKRequestMethodGET path:path parameters:parameters]; + [operation setCompletionBlockWithSuccess:success failure:failure]; + [self enqueueObjectRequestOperation:operation]; +} + +- (void)postObject:(id)object + path:(NSString *)path + parameters:(NSDictionary *)parameters + success:(void (^)(RKObjectRequestOperation *operation, RKMappingResult *mappingResult))success + failure:(void (^)(RKObjectRequestOperation *operation, NSError *error))failure +{ + NSAssert(object || path, @"Cannot make a request without an object or a path."); + RKObjectRequestOperation *operation = [self appropriateObjectRequestOperationWithObject:object method:RKRequestMethodPOST path:path parameters:parameters]; + [operation setCompletionBlockWithSuccess:success failure:failure]; + [self enqueueObjectRequestOperation:operation]; +} + +- (void)putObject:(id)object + path:(NSString *)path + parameters:(NSDictionary *)parameters + success:(void (^)(RKObjectRequestOperation *operation, RKMappingResult *mappingResult))success + failure:(void (^)(RKObjectRequestOperation *operation, NSError *error))failure +{ + NSAssert(object || path, @"Cannot make a request without an object or a path."); + RKObjectRequestOperation *operation = [self appropriateObjectRequestOperationWithObject:object method:RKRequestMethodPUT path:path parameters:parameters]; + [operation setCompletionBlockWithSuccess:success failure:failure]; + [self enqueueObjectRequestOperation:operation]; +} + +- (void)patchObject:(id)object + path:(NSString *)path + parameters:(NSDictionary *)parameters + success:(void (^)(RKObjectRequestOperation *operation, RKMappingResult *mappingResult))success + failure:(void (^)(RKObjectRequestOperation *operation, NSError *error))failure +{ + NSAssert(object || path, @"Cannot make a request without an object or a path."); + RKObjectRequestOperation *operation = [self appropriateObjectRequestOperationWithObject:object method:RKRequestMethodPATCH path:path parameters:parameters]; + [operation setCompletionBlockWithSuccess:success failure:failure]; + [self enqueueObjectRequestOperation:operation]; +} + +- (void)deleteObject:(id)object + path:(NSString *)path + parameters:(NSDictionary *)parameters + success:(void (^)(RKObjectRequestOperation *operation, RKMappingResult *mappingResult))success + failure:(void (^)(RKObjectRequestOperation *operation, NSError *error))failure +{ + NSAssert(object || path, @"Cannot make a request without an object or a path."); + RKObjectRequestOperation *operation = [self appropriateObjectRequestOperationWithObject:object method:RKRequestMethodDELETE path:path parameters:parameters]; + [operation setCompletionBlockWithSuccess:success failure:failure]; + [self enqueueObjectRequestOperation:operation]; +} + +- (RKPaginator *)paginatorWithPathPattern:(NSString *)pathPattern +{ + return [self paginatorWithPathPattern:pathPattern parameters:nil]; +} + +- (RKPaginator *)paginatorWithPathPattern:(NSString *)pathPattern parameters:(NSDictionary *)parameters +{ + NSAssert(self.paginationMapping, @"Cannot instantiate a paginator when `paginationMapping` is nil."); + NSMutableURLRequest *request = [self requestWithMethod:@"GET" path:pathPattern parameters:parameters]; + RKPaginator *paginator = [[self.paginationMapping.objectClass alloc] initWithRequest:request paginationMapping:self.paginationMapping responseDescriptors:self.responseDescriptors]; +#ifdef RKCoreDataIncluded + paginator.managedObjectContext = self.managedObjectStore.mainQueueManagedObjectContext; + paginator.managedObjectCache = self.managedObjectStore.managedObjectCache; + paginator.fetchRequestBlocks = self.fetchRequestBlocks; +#endif + paginator.operationQueue = self.operationQueue; + Class HTTPOperationClass = [self requestOperationClassForRequest:request fromRegisteredClasses:self.registeredHTTPRequestOperationClasses]; + if (HTTPOperationClass) [paginator setHTTPOperationClass:HTTPOperationClass]; + return paginator; +} + +#pragma mark - Request & Response Descriptors + +- (NSArray *)requestDescriptors +{ + return [NSArray arrayWithArray:self.mutableRequestDescriptors]; +} + +- (void)addRequestDescriptor:(RKRequestDescriptor *)requestDescriptor +{ + NSParameterAssert(requestDescriptor); + if ([self.requestDescriptors containsObject:requestDescriptor]) return; + NSAssert([requestDescriptor isKindOfClass:[RKRequestDescriptor class]], @"Expected an object of type RKRequestDescriptor, got '%@'", [requestDescriptor class]); + [self.requestDescriptors enumerateObjectsUsingBlock:^(RKRequestDescriptor *registeredDescriptor, NSUInteger idx, BOOL *stop) { + NSAssert(!([registeredDescriptor.objectClass isEqual:requestDescriptor.objectClass] && (requestDescriptor.method == registeredDescriptor.method)), @"Cannot add request descriptor: An existing descriptor is already registered for the class '%@' and HTTP method'%@'.", requestDescriptor.objectClass, RKStringDescribingRequestMethod(requestDescriptor.method)); + }]; + [self.mutableRequestDescriptors addObject:requestDescriptor]; +} + +- (void)addRequestDescriptorsFromArray:(NSArray *)requestDescriptors +{ + for (RKRequestDescriptor *requestDescriptor in requestDescriptors) { + [self addRequestDescriptor:requestDescriptor]; + } +} + +- (void)removeRequestDescriptor:(RKRequestDescriptor *)requestDescriptor +{ + NSParameterAssert(requestDescriptor); + NSAssert([requestDescriptor isKindOfClass:[RKRequestDescriptor class]], @"Expected an object of type RKRequestDescriptor, got '%@'", [requestDescriptor class]); + [self.mutableRequestDescriptors removeObject:requestDescriptor]; +} + +- (NSArray *)responseDescriptors +{ + return [NSArray arrayWithArray:self.mutableResponseDescriptors]; +} + +- (void)addResponseDescriptor:(RKResponseDescriptor *)responseDescriptor +{ + NSParameterAssert(responseDescriptor); + NSAssert([responseDescriptor isKindOfClass:[RKResponseDescriptor class]], @"Expected an object of type RKResponseDescriptor, got '%@'", [responseDescriptor class]); + responseDescriptor.baseURL = self.baseURL; + [self.mutableResponseDescriptors addObject:responseDescriptor]; +} + +- (void)addResponseDescriptorsFromArray:(NSArray *)responseDescriptors +{ + for (RKResponseDescriptor *responseDescriptor in responseDescriptors) { + [self addResponseDescriptor:responseDescriptor]; + } +} + +- (void)removeResponseDescriptor:(RKResponseDescriptor *)responseDescriptor +{ + NSParameterAssert(responseDescriptor); + NSAssert([responseDescriptor isKindOfClass:[RKResponseDescriptor class]], @"Expected an object of type RKResponseDescriptor, got '%@'", [responseDescriptor class]); + [self.mutableResponseDescriptors removeObject:responseDescriptor]; +} + +#pragma mark - Fetch Request Blocks + +#ifdef RKCoreDataIncluded + +- (NSArray *)fetchRequestBlocks +{ + return [NSArray arrayWithArray:self.mutableFetchRequestBlocks]; +} + +- (void)addFetchRequestBlock:(NSFetchRequest *(^)(NSURL *URL))block +{ + NSParameterAssert(block); + [self.mutableFetchRequestBlocks addObject:block]; +} + +#endif + +#pragma mark - Queue Management + +- (void)enqueueObjectRequestOperation:(RKObjectRequestOperation *)objectRequestOperation +{ + [self.operationQueue addOperation:objectRequestOperation]; +} + +- (NSArray *)enqueuedObjectRequestOperationsWithMethod:(RKRequestMethod)method matchingPathPattern:(NSString *)pathPattern +{ + NSMutableArray *matches = [NSMutableArray array]; + RKPathMatcher *pathMatcher = [RKPathMatcher pathMatcherWithPattern:pathPattern]; + for (NSOperation *operation in [self.operationQueue operations]) { + if (![operation isKindOfClass:[RKObjectRequestOperation class]]) { + continue; + } + NSURLRequest *request = [(RKObjectRequestOperation *)operation HTTPRequestOperation].request; + NSString *pathAndQueryString = RKPathAndQueryStringFromURLRelativeToURL([request URL], self.baseURL); + + RKRequestMethod operationMethod = RKRequestMethodFromString([request HTTPMethod]); + if ((method & operationMethod) && [pathMatcher matchesPath:pathAndQueryString tokenizeQueryStrings:NO parsedArguments:nil]) { + [matches addObject:operation]; + } + } + return [matches copy]; +} + +- (void)cancelAllObjectRequestOperationsWithMethod:(RKRequestMethod)method matchingPathPattern:(NSString *)pathPattern +{ + for (RKObjectRequestOperation *operation in [self enqueuedObjectRequestOperationsWithMethod:method matchingPathPattern:pathPattern]) { + [operation cancel]; + } +} + +- (void)enqueueBatchOfObjectRequestOperationsWithRoute:(RKRoute *)route + objects:(NSArray *)objects + progress:(void (^)(NSUInteger numberOfFinishedOperations, + NSUInteger totalNumberOfOperations))progress + completion:(void (^)(NSArray *operations))completion { + NSMutableArray *operations = [[NSMutableArray alloc] initWithCapacity:objects.count]; + for (id object in objects) { + RKObjectRequestOperation *operation = nil; + NSDictionary *interpolatedParameters = nil; + NSURL *URL = [self URLWithRoute:route object:object interpolatedParameters:&interpolatedParameters]; + NSAssert(URL, @"Failed to generate URL for route %@ with object %@", route, object); + if ([route isClassRoute]) { + operation = [self appropriateObjectRequestOperationWithObject:object method:route.method path:[URL relativeString] parameters:nil]; + } else { + operation = [self appropriateObjectRequestOperationWithObject:nil method:route.method path:[URL relativeString] parameters:nil]; + } + operation.mappingMetadata = @{ @"routing": interpolatedParameters, @"route": route }; + [operations addObject:operation]; + } + return [self enqueueBatchOfObjectRequestOperations:operations progress:progress completion:completion]; +} + +- (void)enqueueBatchOfObjectRequestOperations:(NSArray *)operations + progress:(void (^)(NSUInteger numberOfFinishedOperations, NSUInteger totalNumberOfOperations))progress + completion:(void (^)(NSArray *operations))completion { + + __block dispatch_group_t dispatchGroup = dispatch_group_create(); + NSBlockOperation *batchedOperation = [NSBlockOperation blockOperationWithBlock:^{ + dispatch_group_notify(dispatchGroup, dispatch_get_main_queue(), ^{ + if (completion) { + completion(operations); + } + }); +#if !OS_OBJECT_USE_OBJC + dispatch_release(dispatchGroup); +#endif + }]; + + for (RKObjectRequestOperation *operation in operations) { + void (^originalCompletionBlock)(void) = [operation.completionBlock copy]; + __weak RKObjectRequestOperation *weakOperation = operation; + [operation setCompletionBlock:^{ + dispatch_queue_t queue = weakOperation.successCallbackQueue ?: dispatch_get_main_queue(); + dispatch_group_async(dispatchGroup, queue, ^{ + if (originalCompletionBlock) { + originalCompletionBlock(); + } + + __block NSUInteger numberOfFinishedOperations = 0; + [operations enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + if ([(NSOperation *)obj isFinished]) { + numberOfFinishedOperations++; + } + }]; + + if (progress) { + progress(numberOfFinishedOperations, [operations count]); + } + + dispatch_group_leave(dispatchGroup); + }); + }]; + + dispatch_group_enter(dispatchGroup); + [batchedOperation addDependency:operation]; + + [self enqueueObjectRequestOperation:operation]; + } + [self.operationQueue addOperation:batchedOperation]; +} + +@end + +#ifdef _SYSTEMCONFIGURATION_H +NSString *RKStringFromNetworkReachabilityStatus(AFNetworkReachabilityStatus networkReachabilityStatus) +{ + switch (networkReachabilityStatus) { + case AFNetworkReachabilityStatusNotReachable: return @"Not Reachable"; + case AFNetworkReachabilityStatusReachableViaWiFi: return @"Reachable via WiFi"; + case AFNetworkReachabilityStatusReachableViaWWAN: return @"Reachable via WWAN"; + case AFNetworkReachabilityStatusUnknown: return @"Reachability Unknown"; + default: break; + } + return nil; +} +#endif diff --git a/Pods/RestKit/Code/Network/RKObjectParameterization.h b/Pods/RestKit/Code/Network/RKObjectParameterization.h new file mode 100644 index 0000000..5e9c68f --- /dev/null +++ b/Pods/RestKit/Code/Network/RKObjectParameterization.h @@ -0,0 +1,44 @@ +// +// RKObjectParameterization.h +// RestKit +// +// Created by Blake Watters on 5/2/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKRequestDescriptor.h" + +/** + The `RKObjectParameterization` class provides an interface for mapping a local domain object into an `NSDictionary` representation suitable for use as the parameters of an HTTP request. + */ +@interface RKObjectParameterization : NSObject + +///------------------------------- +/// @name Parameterizing an Object +///------------------------------- + +/** + Returns a dictionary representation of the given object by performing object mapping using the mapping + from the given request descriptor. If the request descriptor specifies a root key path, the mapped parameters + will be nested within the dictionary under the specified root key path. + + @param object The object to be parameterized. + @param requestDescriptor The request descriptor describing how the object is to be mapped into an `NSDictionary` of parameters. + @param error If there is a problem mapping the parameters, upon return contains a pointer to an instance of `NSError` that describes the problem. + @return A new dictionary containing the mapped parameters or nil if an error has occurred. + */ ++ (NSDictionary *)parametersWithObject:(id)object requestDescriptor:(RKRequestDescriptor *)requestDescriptor error:(NSError **)error; + +@end diff --git a/Pods/RestKit/Code/Network/RKObjectParameterization.m b/Pods/RestKit/Code/Network/RKObjectParameterization.m new file mode 100644 index 0000000..857c81a --- /dev/null +++ b/Pods/RestKit/Code/Network/RKObjectParameterization.m @@ -0,0 +1,151 @@ +// +// RKObjectParameterization.m +// RestKit +// +// Created by Blake Watters on 5/2/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKMIMETypes.h" +#import "RKSerialization.h" +#import "RKObjectParameterization.h" +#import "RKMIMETypeSerialization.h" +#import "RKLog.h" +#import "RKObjectMappingOperationDataSource.h" +#import "RKObjectMapping.h" +#import "RKMappingOperation.h" +#import "RKMappingErrors.h" +#import "RKPropertyInspector.h" +#import "RKValueTransformers.h" + +// Set Logging Component +#undef RKLogComponent +#define RKLogComponent RKlcl_cRestKitNetwork + +@interface RKObjectParameterization () <RKMappingOperationDelegate> +@property (nonatomic, strong) id object; +@property (nonatomic, strong) RKRequestDescriptor *requestDescriptor; + +- (instancetype)initWithObject:(id)object requestDescriptor:(RKRequestDescriptor *)requestDescriptor; +- (NSDictionary *)mapObjectToParameters:(NSError **)error; + +// Convenience methods +@property (nonatomic, readonly) RKObjectMapping *mapping; +@property (nonatomic, readonly) NSString *rootKeyPath; +@end + +@implementation RKObjectParameterization + ++ (NSDictionary *)parametersWithObject:(id)object requestDescriptor:(RKRequestDescriptor *)requestDescriptor error:(NSError **)error +{ + RKObjectParameterization *parameterization = [[self alloc] initWithObject:object requestDescriptor:requestDescriptor]; + return [parameterization mapObjectToParameters:error]; +} + +- (instancetype)initWithObject:(id)object requestDescriptor:(RKRequestDescriptor *)requestDescriptor +{ + NSParameterAssert(object); + NSParameterAssert(requestDescriptor); + + self = [super init]; + if (self) { + self.object = object; + self.requestDescriptor = requestDescriptor; + } + return self; +} + +- (RKMapping *)mapping +{ + return self.requestDescriptor.mapping; +} + +- (NSString *)rootKeyPath +{ + return self.requestDescriptor.rootKeyPath; +} + +- (NSDictionary *)mapObjectToParameters:(NSError **)error +{ + RKObjectMappingOperationDataSource *dataSource = [RKObjectMappingOperationDataSource new]; + NSMutableDictionary *dictionary = [NSMutableDictionary dictionary]; + RKMappingOperation *operation = [[RKMappingOperation alloc] initWithSourceObject:self.object destinationObject:dictionary mapping:self.mapping]; + operation.dataSource = dataSource; + operation.delegate = self; + [operation start]; + if (operation.error) { + if (operation.error.code == RKMappingErrorUnmappableRepresentation) { + // If the mapped object is empty, return an empty dictionary and no error + return self.rootKeyPath ? @{ self.rootKeyPath: @{} } : @{}; + } + + if (error) *error = operation.error; + return nil; + } + + // Optionally enclose the serialized object within a container... + return self.rootKeyPath ? [NSMutableDictionary dictionaryWithObject:dictionary forKey:self.rootKeyPath] : dictionary; +} + +#pragma mark - RKMappingOperationDelegate + +- (void)mappingOperation:(RKMappingOperation *)operation didSetValue:(id)value forKeyPath:(NSString *)keyPath usingMapping:(RKAttributeMapping *)mapping +{ + id transformedValue = nil; + if (value == nil) { + if (mapping.objectMapping.assignsDefaultValueForMissingAttributes) { + // Serialize nil values as null + transformedValue = [NSNull null]; + } + } else if ([value isKindOfClass:[NSDate class]]) { + [mapping.valueTransformer transformValue:value toValue:&transformedValue ofClass:[NSString class] error:nil]; + } else if ([value isKindOfClass:[NSDecimalNumber class]]) { + // Precision numbers are serialized as strings to work around Javascript notation limits + transformedValue = [(NSDecimalNumber *)value stringValue]; + } else if ([value isKindOfClass:[NSSet class]]) { + // NSSets are not natively serializable, so let's just turn it into an NSArray + transformedValue = [value allObjects]; + } else if ([value isKindOfClass:[NSOrderedSet class]]) { + // NSOrderedSets are not natively serializable, so let's just turn it into an NSArray + transformedValue = [value array]; + } else { + Class propertyClass = RKPropertyInspectorGetClassForPropertyAtKeyPathOfObject(mapping.sourceKeyPath, operation.sourceObject); + if ([propertyClass isSubclassOfClass:NSClassFromString(@"__NSCFBoolean")] || [propertyClass isSubclassOfClass:NSClassFromString(@"NSCFBoolean")]) { + transformedValue = @([value boolValue]); + } + } + + if (transformedValue) { + RKLogDebug(@"Serialized %@ value at keyPath to %@ (%@)", NSStringFromClass([value class]), NSStringFromClass([transformedValue class]), value); + [operation.destinationObject setValue:transformedValue forKeyPath:keyPath]; + } +} + +- (BOOL)mappingOperation:(RKMappingOperation *)operation shouldSetValue:(id)value forKeyPath:(NSString *)keyPath usingMapping:(RKPropertyMapping *)propertyMapping +{ + NSArray *keyPathComponents = [keyPath componentsSeparatedByString:@"."]; + id currentValue = operation.destinationObject; + for (NSString *key in keyPathComponents) { + id value = [currentValue valueForKey:key]; + if (value == nil) { + value = [NSMutableDictionary new]; + [currentValue setValue:value forKey:key]; + } + currentValue = value; + } + return YES; +} + +@end diff --git a/Pods/RestKit/Code/Network/RKObjectRequestOperation.h b/Pods/RestKit/Code/Network/RKObjectRequestOperation.h new file mode 100644 index 0000000..ea0d17b --- /dev/null +++ b/Pods/RestKit/Code/Network/RKObjectRequestOperation.h @@ -0,0 +1,238 @@ +// +// RKObjectRequestOperation.h +// RestKit +// +// Created by Blake Watters on 8/9/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKHTTPRequestOperation.h" +#import "RKMappingResult.h" +#import "RKMapperOperation.h" + +/** + The key for a Boolean NSNumber value that indicates if a `NSCachedURLResponse` stored in the `NSURLCache` has been object mapped to completion. This key is stored on the `userInfo` of the cached response, if any, just before an `RKObjectRequestOperation` transitions to the finished state. + */ +extern NSString * const RKResponseHasBeenMappedCacheUserInfoKey; + +/** + `RKObjectRequestOperation` is an `NSOperation` subclass that implements object mapping on the response body of an `NSHTTPResponse` loaded via an `RKHTTPRequestOperation`. + + Object request operations are initialized with a fully configured `NSURLRequest` object and an array of `RKResponseDescriptor` objects. `RKObjectRequestOperation` is internally implemented as an aggregate operation that constructs and starts an `RKHTTPRequestOperation` to perform the network access and retrieve the mappable data. If an error occurs during HTTP transport, the object request operation is failed with the transport error. Once response data is loaded for the request, the object request operation creates and starts an `RKObjectResponseMapperOperation` to perform the object mapping on the response body. If the mapping operation fails, then object request operation is failed and the `error` property is set. If mapping is successful, then the `mappingResult` property is set and the operation is finished successfully. + + ## Acceptable Content Types and Status Codes + + Instances of `RKObjectRequestOperation` determine the acceptability of status codes and content types differently than is typical for `AFNetworking` derived network opertations. The `RKHTTPRequestOperation` (which is a subclass of the AFNetworking `AFHTTPRequestOperation` class) supports the dynamic assignment of acceptable status codes and content types. This facility is utilized during the configuration of the network operation for an object request operation. The set of acceptable content types is determined by consulting the `RKMIMETypeSerialization` via an invocation of `[RKMIMETypeSerialization registeredMIMETypes]`. The `registeredMIMETypes` method returns an `NSSet` containing either `NSString` or `NSRegularExpression` objects that specify the content types for which `RKSerialization` classes have been registered to handle. The set of acceptable status codes is determined by aggregating the value of the `statusCodes` property from all registered `RKResponseDescriptor` objects. + + ## Error Mapping + + If the HTTP request returned a response in the Client Error (400-499 range) or Server Error (500-599 range) class and an appropriate `RKResponseDescriptor` is provided to perform mapping on the response, then the object mapping result is considered to contain a server returned error. In this case, an `NSError` object is created in the `RKErrorDomain` with an error code of `RKMappingErrorFromMappingResult` and the object request operation is failed. In the event that an a response is returned in an error class and no `RKResponseDescriptor` has been provided to the operation to handle it, then an `NSError` object in the `AFNetworkingErrorDomain` with an error code of `NSURLErrorBadServerResponse` will be returned by the underlying `RKHTTPRequestOperation` indicating that an unexpected status code was returned. + + ## Metadata Mapping + + The `RKObjectRequestOperation` class provides support for metadata mapping via the `mappingMetadata` property. This optional dictionary of user supplied information is made available to the mapping operations executed when processing the HTTP response loaded by an object request operation. More details about the metadata mapping architecture is available on the `RKMappingOperation` documentation. + + ## Prioritization and Cancellation + + Object request operations support prioritization and cancellation of the underlying `RKHTTPRequestOperation` and `RKResponseMapperOperation` operations that perform the network transport and object mapping duties on their behalf. The queue priority of the object request operation, as set via the `[NSOperation setQueuePriority:]` method, is applied to the underlying response mapping operation when it is enqueued onto the `responseMappingQueue`. If the object request operation is cancelled, then the underlying HTTP request operation and response mapping operation are also cancelled. + + ## Caching + + Instances of `RKObjectRequestOperation` support all the HTTP caching facilities available via the `NSURLConnection` family of API's. For caching to be enabled, the remote web server that the application is communicating with must emit the appropriate `Cache-Control`, `Expires`, and/or `ETag` headers. When the response headers include the appropriate caching information, the shared `NSURLCache` instance will manage responses and transparently add conditional GET support to cachable requests. HTTP caching is a deep topic explored in depth across the web and detailed in RFC 2616: http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html + + The `RKObjectRequestOperation` class also provides support for utilizing the `NSURLCache` to satisfy requests without hitting the network. This support enables applications to display views presenting data retrieved via a cachable `GET` request without revalidating with the server and incurring any overhead. The optimization is controlled via `avoidsNetworkAccess` property. When enabled, the operation will skip the network transport portion of the object request operation and proceed directly to object mapping the cached response data. When the object request operation is an instance of `RKManagedObjectRequestOperation`, the deserialization and mapping portion of the process can be skipped entirely and the operation will fetch the appropriate object directly from Core Data, falling back to network transport once the cache entry has expired. Please refer to the documentation accompanying `RKManagedObjectRequestOperation` for more details. + + ## Core Data + + `RKObjectRequestOperation` is not able to perform object mapping that targets Core Data destination entities. Please refer to the `RKManagedObjectRequestOperation` subclass for details regarding performing a Core Data object request operation. + + ## Subclassing Notes + + The `RKObjectRequestOperation` is a non-current `NSOperation` subclass and can be extended by subclassing and providing an implementation of the `main` method. It conforms to the `RKMapperOperationDelegate` protocol, providing access to the lifecycle of the mapping process to subclasses. + + @see `RKResponseDescriptor` + @see `RKHTTPRequestOperation` + @see `RKMIMETypeSerialization` + @see `RKManagedObjectRequestOperation` + */ +@interface RKObjectRequestOperation : NSOperation <NSCopying, RKMapperOperationDelegate> { + @protected + RKMappingResult *_mappingResult; +} + +///----------------------------------------------- +/// @name Initializing an Object Request Operation +///----------------------------------------------- + +/** + Initializes an object request operation with an HTTP request operation and a set of response descriptors. + + This is the designated initializer. + + @param requestOperation The request object to be used with the underlying network operation. + @param responseDescriptors An array of `RKResponseDescriptor` objects specifying how object mapping is to be performed on the response loaded by the network operation. + @return The receiver, initialized with the given request and response descriptors. + */ +- (instancetype)initWithHTTPRequestOperation:(RKHTTPRequestOperation *)requestOperation responseDescriptors:(NSArray *)responseDescriptors; + +/** + Initializes an object request operation with a request object and a set of response descriptors. + + This method is a convenience initializer for initializing an object request operation from a URL request with the default HTTP operation class `RKHTTPRequestOperation`. This method is functionally equivalent to the following example code: + + RKHTTPRequestOperation *requestOperation = [[RKHTTPRequestOperation alloc] initWithRequest:request]; + RKObjectRequestOperation *objectRequestOperation = [[RKObjectRequestOperation alloc] initWithHTTPRequestOperation:requestOperation responseDescriptors:responseDescriptors]; + + @param request The request object to be used with the underlying network operation. + @param responseDescriptors An array of `RKResponseDescriptor` objects specifying how object mapping is to be performed on the response loaded by the network operation. + @return The receiver, initialized with the given request and response descriptors. + */ +- (instancetype)initWithRequest:(NSURLRequest *)request responseDescriptors:(NSArray *)responseDescriptors; + +///--------------------------------- +/// @name Configuring Object Mapping +///--------------------------------- + +/** + The array of `RKResponseDescriptor` objects that specify how the deserialized `responseData` is to be object mapped. + + The response descriptors define the acceptable HTTP Status Codes of the receiver. + */ +@property (nonatomic, strong, readonly) NSArray *responseDescriptors; + +/** + The target object for the object mapping operation. + + @see `[RKObjectResponseMapperOperation targetObject]` + */ +@property (nonatomic, strong) id targetObject; + +/** + An optional dictionary of metadata to make available to mapping operations executed while processing the HTTP response loaded by the receiver. + */ +@property (nonatomic, copy) NSDictionary *mappingMetadata; + +///---------------------------------- +/// @name Accessing Operation Results +///---------------------------------- + +/** + The mapping result returned by the underlying `RKObjectResponseMapperOperation`. + + This property is `nil` if the operation is failed due to a network transport error or no mapping was peformed on the response. + */ +@property (nonatomic, strong, readonly) RKMappingResult *mappingResult; + +/** + The error, if any, that occurred during execution of the operation. + + Errors may originate during the network transport or object mapping phases of the object request operation. A `nil` error value indicates that the operation completed successfully. + */ +@property (nonatomic, strong, readonly) NSError *error; + +///------------------------------------------- +/// @name Accessing the HTTP Request Operation +///------------------------------------------- + +/** + The underlying `RKHTTPRequestOperation` object used to manage the HTTP request/response lifecycle of the object request operation. + */ +@property (nonatomic, strong, readonly) RKHTTPRequestOperation *HTTPRequestOperation; + +///------------------------------------------------------- +/// @name Setting the Completion Block and Callback Queues +///------------------------------------------------------- + +/** + Sets the `completionBlock` property with a block that executes either the specified success or failure block, depending on the state of the object request on completion. If `error` returns a value, which can be set during HTTP transport by the underlying `HTTPRequestOperation` or during object mapping by the `RKResponseMapperOperation` object, then `failure` is executed. If the object request operation is cancelled, then the failure block will be executed with either a `RKOperationCancelledError` or a `NSURLErrorCancelled`, depending on the internal state of the operation at time of cancellation. Otherwise, `success` is executed. + + @param success The block to be executed on the completion of a successful operation. This block has no return value and takes two arguments: the receiver operation and the mapping result from object mapping the response data of the request. + @param failure The block to be executed on the completion of an unsuccessful operation. This block has no return value and takes two arguments: the receiver operation and the error that occurred during the execution of the operation. + */ +- (void)setCompletionBlockWithSuccess:(void (^)(RKObjectRequestOperation *operation, RKMappingResult *mappingResult))success + failure:(void (^)(RKObjectRequestOperation *operation, NSError *error))failure; + +/** + The callback dispatch queue on success. If `NULL` (default), the main queue is used. + + The queue is retained while this operation is living + */ +@property (nonatomic, assign) dispatch_queue_t successCallbackQueue; + +/** + The callback dispatch queue on failure. If `NULL` (default), the main queue is used. + + The queue is retained while this operation is living + */ +@property (nonatomic, assign) dispatch_queue_t failureCallbackQueue; + +/** + Sets a block to be executed before the object request operation begins mapping the deserialized response body, providing an opportunity to manipulate the mappable representation input that will be passed to the response mapper. + + @param block A block object to be executed before the deserialized response is passed to the response mapper. The block has an `id` return type and must return a dictionary or array of dictionaries corresponding to the object representations that are to be mapped. The block accepts a single argument: the deserialized response data that was loaded via HTTP. If you do not wish to make any chances to the response body before mapping begins, the block should return the value passed in the `deserializedResponseBody` block argument. Returning `nil` will decline the mapping from proceeding and fail the operation with an error with the `RKMappingErrorMappingDeclined` code. + @see [RKResponseMapperOperation setWillMapDeserializedResponseBlock:] + @warning The deserialized response body may or may not be immutable depending on the implementation details of the `RKSerialization` class that deserialized the response. If you wish to make changes to the mappable object representations, you must obtain a mutable copy of the response body input. + */ +- (void)setWillMapDeserializedResponseBlock:(id (^)(id deserializedResponseBody))block; + +///----------------------------------------------------- +/// @name Determining Whether a Request Can Be Processed +///----------------------------------------------------- + +/** + Returns a Boolean value determining whether or not the class can process the specified request. + + @param request The request that is determined to be supported or not supported for this class. + */ ++ (BOOL)canProcessRequest:(NSURLRequest *)request; + +///------------------------------------------- +/// @name Accessing the Response Mapping Queue +///------------------------------------------- + +/** + Returns the operation queue used by all object request operations when object mapping the body of a response loaded via HTTP. + + By default, the response mapping queue is configured with a maximum concurrent operation count of 1, ensuring that only one HTTP response is mapped at a time. + + @return The response mapping queue. + */ ++ (NSOperationQueue *)responseMappingQueue; + +@end + +///-------------------- +/// @name Notifications +///-------------------- + +/** + Posted when an object request operation begin executing. + */ +extern NSString *const RKObjectRequestOperationDidStartNotification; + +/** + Posted when an object request operation finishes. + */ +extern NSString *const RKObjectRequestOperationDidFinishNotification; + +/** + The key for an `NSDate` object specifying the time at which object mapping started for object request operation. Available in the user info dictionary of an `RKObjectRequestOperationDidFinishNotification` + */ +extern NSString *const RKObjectRequestOperationMappingDidStartUserInfoKey; + +/** + The key for an `NSDate` object specifying the time at which object mapping finished for object request operation. Available in the user info dictionary of an `RKObjectRequestOperationDidFinishNotification` + */ +extern NSString *const RKObjectRequestOperationMappingDidFinishUserInfoKey; diff --git a/Pods/RestKit/Code/Network/RKObjectRequestOperation.m b/Pods/RestKit/Code/Network/RKObjectRequestOperation.m new file mode 100644 index 0000000..8fbeda8 --- /dev/null +++ b/Pods/RestKit/Code/Network/RKObjectRequestOperation.m @@ -0,0 +1,645 @@ +// +// RKObjectRequestOperation.m +// RestKit +// +// Created by Blake Watters on 8/9/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import <objc/runtime.h> +#import "RKObjectRequestOperation.h" +#import "RKResponseMapperOperation.h" +#import "RKResponseDescriptor.h" +#import "RKMIMETypeSerialization.h" +#import "RKHTTPUtilities.h" +#import "RKLog.h" +#import "RKMappingErrors.h" +#import "RKOperationStateMachine.h" + +#import <Availability.h> + +#if __IPHONE_OS_VERSION_MIN_REQUIRED +#import "AFNetworkActivityIndicatorManager.h" +#endif + +// Set Logging Component +#undef RKLogComponent +#define RKLogComponent RKlcl_cRestKitNetwork + +static BOOL RKLogIsStringBlank(NSString *string) +{ + return ([[string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] length] == 0); +} + +static NSString *RKLogTruncateString(NSString *string) +{ + static NSInteger maxMessageLength; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + NSDictionary *envVars = [[NSProcessInfo processInfo] environment]; + maxMessageLength = RKLogIsStringBlank(envVars[@"RKLogMaxLength"]) ? NSIntegerMax : [envVars[@"RKLogMaxLength"] integerValue]; + }); + + return ([string length] <= maxMessageLength) + ? string + : [NSString stringWithFormat:@"%@... (truncated at %ld characters)", + [string substringToIndex:maxMessageLength], + (long) maxMessageLength]; +} + +@interface NSCachedURLResponse (RKLeakFix) + +@property (NS_NONATOMIC_IOSONLY, readonly, copy) NSData *rkData; + +@end + +@interface RKObjectRequestOperationLogger : NSObject + ++ (RKObjectRequestOperationLogger*)sharedLogger; + +@end + +@implementation RKObjectRequestOperationLogger + ++ (RKObjectRequestOperationLogger*)sharedLogger +{ + static RKObjectRequestOperationLogger *sharedInstance = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedInstance = [[self alloc] init]; + }); + return sharedInstance; +} + ++ (void)load +{ + @autoreleasepool { + [self sharedLogger]; + }; +} + +- (instancetype)init +{ + self = [super init]; + if (self) { + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(objectRequestOperationDidStart:) + name:RKObjectRequestOperationDidStartNotification + object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(objectRequestOperationDidFinish:) + name:RKObjectRequestOperationDidFinishNotification + object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(HTTPOperationDidStart:) + name:AFNetworkingOperationDidStartNotification + object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(HTTPOperationDidFinish:) + name:AFNetworkingOperationDidFinishNotification + object:nil]; + } + + return self; +} + +- (void)dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + +static void *RKParentObjectRequestOperation = &RKParentObjectRequestOperation; +static void *RKOperationStartDate = &RKOperationStartDate; +static void *RKOperationFinishDate = &RKOperationFinishDate; + +- (void)objectRequestOperationDidStart:(NSNotification *)notification +{ + // Weakly tag the HTTP operation with its parent object request operation + RKObjectRequestOperation *objectRequestOperation = [notification object]; + objc_setAssociatedObject(objectRequestOperation, RKOperationStartDate, [NSDate date], OBJC_ASSOCIATION_RETAIN_NONATOMIC); + objc_setAssociatedObject(objectRequestOperation.HTTPRequestOperation, RKParentObjectRequestOperation, objectRequestOperation, OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + +- (void)HTTPOperationDidStart:(NSNotification *)notification +{ + RKHTTPRequestOperation *operation = [notification object]; + if (![operation isKindOfClass:[AFHTTPRequestOperation class]]) return; + + objc_setAssociatedObject(operation, RKOperationStartDate, [NSDate date], OBJC_ASSOCIATION_RETAIN_NONATOMIC); + + if ((_RKlcl_component_level[(__RKlcl_log_symbol(RKlcl_cRestKitNetwork))]) >= (__RKlcl_log_symbol(RKlcl_vTrace))) { + NSString *body = nil; + if ([operation.request HTTPBody]) { + body = RKLogTruncateString([[NSString alloc] initWithData:[operation.request HTTPBody] encoding:NSUTF8StringEncoding]); + } + + RKLogTrace(@"%@ '%@':\nrequest.headers=%@\nrequest.body=%@", [operation.request HTTPMethod], [[operation.request URL] absoluteString], [operation.request allHTTPHeaderFields], body); + } else { + RKLogInfo(@"%@ '%@'", [operation.request HTTPMethod], [[operation.request URL] absoluteString]); + } +} + +- (void)HTTPOperationDidFinish:(NSNotification *)notification +{ + RKHTTPRequestOperation *operation = [notification object]; + if (![operation isKindOfClass:[AFHTTPRequestOperation class]]) return; + + // NOTE: if we have a parent object request operation, we'll wait it to finish to emit the logging info + RKObjectRequestOperation *parentOperation = objc_getAssociatedObject(operation, RKParentObjectRequestOperation); + objc_setAssociatedObject(operation, RKParentObjectRequestOperation, nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + if (parentOperation) { + objc_setAssociatedObject(operation, RKOperationFinishDate, [NSDate date], OBJC_ASSOCIATION_RETAIN_NONATOMIC); + return; + } + + NSTimeInterval elapsedTime = [[NSDate date] timeIntervalSinceDate:objc_getAssociatedObject(operation, RKOperationStartDate)]; + + NSString *statusCodeString = RKStringFromStatusCode([operation.response statusCode]); + NSString *elapsedTimeString = [NSString stringWithFormat:@"[%.04f s]", elapsedTime]; + NSString *statusCodeAndElapsedTime = statusCodeString ? [NSString stringWithFormat:@"(%ld %@) %@", (long)[operation.response statusCode], statusCodeString, elapsedTimeString] : [NSString stringWithFormat:@"(%ld) %@", (long)[operation.response statusCode], elapsedTimeString]; + if (operation.error) { + if ((_RKlcl_component_level[(__RKlcl_log_symbol(RKlcl_cRestKitNetwork))]) >= (__RKlcl_log_symbol(RKlcl_vTrace))) { + RKLogError(@"%@ '%@' %@:\nerror=%@", [operation.request HTTPMethod], [[operation.request URL] absoluteString], statusCodeAndElapsedTime, operation.error); + RKLogDebug(@"response.body=%@", operation.responseString); + } else { + if (operation.error.code == NSURLErrorCancelled) { + RKLogError(@"%@ '%@' %@: Cancelled", [operation.request HTTPMethod], [[operation.request URL] absoluteString], statusCodeAndElapsedTime); + } else { + RKLogError(@"%@ '%@' %@: %@", [operation.request HTTPMethod], [[operation.request URL] absoluteString], statusCodeAndElapsedTime, operation.error); + } + } + } else { + if ((_RKlcl_component_level[(__RKlcl_log_symbol(RKlcl_cRestKitNetwork))]) >= (__RKlcl_log_symbol(RKlcl_vTrace))) { + RKLogTrace(@"%@ '%@' %@:\nresponse.headers=%@\nresponse.body=%@", [operation.request HTTPMethod], [[operation.request URL] absoluteString], statusCodeAndElapsedTime, [operation.response allHeaderFields], RKLogTruncateString(operation.responseString)); + } else { + RKLogInfo(@"%@ '%@' %@", [operation.request HTTPMethod], [[operation.request URL] absoluteString], statusCodeAndElapsedTime); + } + } +} + +- (void)objectRequestOperationDidFinish:(NSNotification *)notification +{ + RKObjectRequestOperation *objectRequestOperation = [notification object]; + if (![objectRequestOperation isKindOfClass:[RKObjectRequestOperation class]]) return; + + RKHTTPRequestOperation *HTTPRequestOperation = objectRequestOperation.HTTPRequestOperation; + NSTimeInterval objectRequestExecutionDuration = [[NSDate date] timeIntervalSinceDate:objc_getAssociatedObject(objectRequestOperation, RKOperationStartDate)]; + NSTimeInterval httpRequestExecutionDuration = [objc_getAssociatedObject(HTTPRequestOperation, RKOperationFinishDate) timeIntervalSinceDate:objc_getAssociatedObject(HTTPRequestOperation, RKOperationStartDate)]; + NSDate *mappingDidStartTime = (notification.userInfo)[RKObjectRequestOperationMappingDidFinishUserInfoKey]; + NSTimeInterval mappingDuration = [mappingDidStartTime isEqual:[NSNull null]] ? 0.0 : [mappingDidStartTime timeIntervalSinceDate:(notification.userInfo)[RKObjectRequestOperationMappingDidStartUserInfoKey]]; + + NSString *statusCodeString = RKStringFromStatusCode([HTTPRequestOperation.response statusCode]); + NSString *statusCodeDescription = statusCodeString ? [NSString stringWithFormat:@" %@ ", statusCodeString] : @" "; + NSString *elapsedTimeString = [NSString stringWithFormat:@"[request=%.04fs mapping=%.04fs total=%.04fs]", httpRequestExecutionDuration, mappingDuration, objectRequestExecutionDuration]; + NSString *statusCodeAndElapsedTime = [NSString stringWithFormat:@"(%ld%@/ %lu objects) %@", (long)[HTTPRequestOperation.response statusCode], statusCodeDescription, (unsigned long) [objectRequestOperation.mappingResult count], elapsedTimeString]; + if (objectRequestOperation.error) { + if ((_RKlcl_component_level[(__RKlcl_log_symbol(RKlcl_cRestKitNetwork))]) >= (__RKlcl_log_symbol(RKlcl_vTrace))) { + RKLogError(@"%@ '%@' %@:\nerror=%@", [HTTPRequestOperation.request HTTPMethod], [[HTTPRequestOperation.request URL] absoluteString], statusCodeAndElapsedTime, objectRequestOperation.error); + RKLogDebug(@"response.body=%@", HTTPRequestOperation.responseString); + } else { + if (objectRequestOperation.error.code == NSURLErrorCancelled) { + RKLogError(@"%@ '%@' %@: Cancelled", [HTTPRequestOperation.request HTTPMethod], [[HTTPRequestOperation.request URL] absoluteString], statusCodeAndElapsedTime); + } else { + RKLogError(@"%@ '%@' %@: %@", [HTTPRequestOperation.request HTTPMethod], [[HTTPRequestOperation.request URL] absoluteString], statusCodeAndElapsedTime, objectRequestOperation.error); + } + } + } else { + if ((_RKlcl_component_level[(__RKlcl_log_symbol(RKlcl_cRestKitNetwork))]) >= (__RKlcl_log_symbol(RKlcl_vTrace))) { + RKLogTrace(@"%@ '%@' %@:\nresponse.headers=%@\nresponse.body=%@", [HTTPRequestOperation.request HTTPMethod], [[HTTPRequestOperation.request URL] absoluteString], statusCodeAndElapsedTime, [HTTPRequestOperation.response allHeaderFields], RKLogTruncateString(HTTPRequestOperation.responseString)); + } else { + RKLogInfo(@"%@ '%@' %@", [HTTPRequestOperation.request HTTPMethod], [[HTTPRequestOperation.request URL] absoluteString], statusCodeAndElapsedTime); + } + } +} + +@end + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +NSString *const RKObjectRequestOperationDidStartNotification = @"RKObjectRequestOperationDidStartNotification"; +NSString *const RKObjectRequestOperationDidFinishNotification = @"RKObjectRequestOperationDidFinishNotification"; +NSString *const RKResponseHasBeenMappedCacheUserInfoKey = @"RKResponseHasBeenMapped"; +NSString *const RKObjectRequestOperationMappingDidStartUserInfoKey = @"mappingStartedAt"; +NSString *const RKObjectRequestOperationMappingDidFinishUserInfoKey = @"mappingFinishedAt"; + +static void RKIncrementNetworkActivityIndicator() +{ + #if __IPHONE_OS_VERSION_MIN_REQUIRED + [[AFNetworkActivityIndicatorManager sharedManager] incrementActivityCount]; + #endif +} + +static void RKDecrementNetworkAcitivityIndicator() +{ + #if __IPHONE_OS_VERSION_MIN_REQUIRED + [[AFNetworkActivityIndicatorManager sharedManager] decrementActivityCount]; + #endif +} + +static NSIndexSet *RKAcceptableStatusCodesFromResponseDescriptors(NSArray *responseDescriptors) +{ + // If there are no response descriptors or any descriptor matches any status code (expressed by `statusCodes` == `nil`) then we want to accept anything + if ([responseDescriptors count] == 0 || [[responseDescriptors valueForKey:@"statusCodes"] containsObject:[NSNull null]]) return nil; + + NSMutableIndexSet *acceptableStatusCodes = [NSMutableIndexSet indexSet]; + [responseDescriptors enumerateObjectsUsingBlock:^(RKResponseDescriptor *responseDescriptor, NSUInteger idx, BOOL *stop) { + [acceptableStatusCodes addIndexes:responseDescriptor.statusCodes]; + }]; + return acceptableStatusCodes; +} + +static NSString *RKStringForStateOfObjectRequestOperation(RKObjectRequestOperation *operation) +{ + if ([operation isExecuting]) { + return @"Executing"; + } else if ([operation isFinished]) { + if (operation.error) { + return @"Failed"; + } else { + return @"Successful"; + } + } else { + return @"Ready"; + } +} + +static NSString *RKStringDescribingURLResponseWithData(NSURLResponse *response, NSData *data) +{ + if ([response isKindOfClass:[NSHTTPURLResponse class]]) { + NSHTTPURLResponse *HTTPResponse = (NSHTTPURLResponse *)response; + return [NSString stringWithFormat:@"<%@: %p statusCode=%ld MIMEType=%@ length=%ld>", [response class], response, (long) [HTTPResponse statusCode], [HTTPResponse MIMEType], (long) [data length]]; + } else { + return [response description]; + } +} + +@interface RKObjectRequestOperation () +@property (nonatomic, strong) RKOperationStateMachine *stateMachine; +@property (nonatomic, strong, readwrite) RKHTTPRequestOperation *HTTPRequestOperation; +@property (nonatomic, strong, readwrite) NSArray *responseDescriptors; +@property (nonatomic, strong, readwrite) RKMappingResult *mappingResult; +@property (nonatomic, strong, readwrite) NSError *error; +@property (nonatomic, strong) RKObjectResponseMapperOperation *responseMapperOperation; +@property (nonatomic, copy) id (^willMapDeserializedResponseBlock)(id deserializedResponseBody); +@property (nonatomic, strong) NSDate *mappingDidStartDate; +@property (nonatomic, strong) NSDate *mappingDidFinishDate; +@property (nonatomic, copy) void (^successBlock)(RKObjectRequestOperation *operation, RKMappingResult *mappingResult); +@property (nonatomic, copy) void (^failureBlock)(RKObjectRequestOperation *operation, NSError *error); +@end + +@implementation RKObjectRequestOperation + ++ (NSOperationQueue *)responseMappingQueue +{ + static NSOperationQueue *responseMappingQueue = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + responseMappingQueue = [NSOperationQueue new]; + [responseMappingQueue setName:@"RKObjectRequestOperation Response Mapping Queue" ]; + [responseMappingQueue setMaxConcurrentOperationCount:1]; + }); + + return responseMappingQueue; +} + ++ (dispatch_queue_t)dispatchQueue +{ + static dispatch_queue_t dispatchQueue; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + dispatchQueue = dispatch_queue_create("org.restkit.network.object-request-operation-queue", DISPATCH_QUEUE_CONCURRENT); + }); + + return dispatchQueue; +} + ++ (BOOL)canProcessRequest:(NSURLRequest *)request +{ + return YES; +} + +- (void)dealloc +{ +#if !OS_OBJECT_USE_OBJC + if (_failureCallbackQueue) dispatch_release(_failureCallbackQueue); + if (_successCallbackQueue) dispatch_release(_successCallbackQueue); +#endif + _failureCallbackQueue = NULL; + _successCallbackQueue = NULL; +} + +// Designated initializer +- (instancetype)initWithHTTPRequestOperation:(RKHTTPRequestOperation *)requestOperation responseDescriptors:(NSArray *)responseDescriptors +{ + NSParameterAssert(requestOperation); + NSParameterAssert(responseDescriptors); + + self = [self init]; + if (self) { + self.responseDescriptors = responseDescriptors; + self.HTTPRequestOperation = requestOperation; + self.HTTPRequestOperation.acceptableContentTypes = [RKMIMETypeSerialization registeredMIMETypes]; + self.HTTPRequestOperation.acceptableStatusCodes = RKAcceptableStatusCodesFromResponseDescriptors(responseDescriptors); + self.HTTPRequestOperation.successCallbackQueue = [[self class] dispatchQueue]; + self.HTTPRequestOperation.failureCallbackQueue = [[self class] dispatchQueue]; + + __weak __typeof(self)weakSelf = self; + self.stateMachine = [[RKOperationStateMachine alloc] initWithOperation:self dispatchQueue:[[self class] dispatchQueue]]; + [self.stateMachine setExecutionBlock:^{ + [[NSNotificationCenter defaultCenter] postNotificationName:RKObjectRequestOperationDidStartNotification object:weakSelf]; + RKIncrementNetworkActivityIndicator(); + if (weakSelf.isCancelled) { + [weakSelf.stateMachine finish]; + } else { + [weakSelf execute]; + } + }]; + [self.stateMachine setFinalizationBlock:^{ + [weakSelf willFinish]; + RKDecrementNetworkAcitivityIndicator(); + [[NSNotificationCenter defaultCenter] postNotificationName:RKObjectRequestOperationDidFinishNotification object:weakSelf userInfo:@{ RKObjectRequestOperationMappingDidStartUserInfoKey: weakSelf.mappingDidStartDate ?: [NSNull null], RKObjectRequestOperationMappingDidFinishUserInfoKey: weakSelf.mappingDidFinishDate ?: [NSNull null] }]; + }]; + [self.stateMachine setCancellationBlock:^{ + [weakSelf.HTTPRequestOperation cancel]; + [weakSelf.responseMapperOperation cancel]; + }]; + } + + return self; +} + +- (instancetype)initWithRequest:(NSURLRequest *)request responseDescriptors:(NSArray *)responseDescriptors +{ + NSParameterAssert(request); + NSParameterAssert(responseDescriptors); + return [self initWithHTTPRequestOperation:[[RKHTTPRequestOperation alloc] initWithRequest:request] responseDescriptors:responseDescriptors]; +} + +- (void)setSuccessCallbackQueue:(dispatch_queue_t)successCallbackQueue +{ + if (successCallbackQueue != _successCallbackQueue) { + if (_successCallbackQueue) { +#if !OS_OBJECT_USE_OBJC + dispatch_release(_successCallbackQueue); +#endif + _successCallbackQueue = NULL; + } + + if (successCallbackQueue) { +#if !OS_OBJECT_USE_OBJC + dispatch_retain(successCallbackQueue); +#endif + _successCallbackQueue = successCallbackQueue; + } + } +} + +- (void)setFailureCallbackQueue:(dispatch_queue_t)failureCallbackQueue +{ + if (failureCallbackQueue != _failureCallbackQueue) { + if (_failureCallbackQueue) { +#if !OS_OBJECT_USE_OBJC + dispatch_release(_failureCallbackQueue); +#endif + _failureCallbackQueue = NULL; + } + + if (failureCallbackQueue) { +#if !OS_OBJECT_USE_OBJC + dispatch_retain(failureCallbackQueue); +#endif + _failureCallbackQueue = failureCallbackQueue; + } + } +} + +// Adopted fix for "The Deallocation Problem" from AFN +- (void)setCompletionBlock:(void (^)(void))block +{ + if (!block) { + [super setCompletionBlock:nil]; + } else { + __unsafe_unretained id weakSelf = self; + [super setCompletionBlock:^ { + block(); + [weakSelf setCompletionBlock:nil]; + }]; + } +} + +- (void)setWillMapDeserializedResponseBlock:(id (^)(id))block +{ + if (!block) { + _willMapDeserializedResponseBlock = nil; + } else { + __unsafe_unretained id weakSelf = self; + _willMapDeserializedResponseBlock = ^id (id deserializedResponse) { + id result = block(deserializedResponse); + [weakSelf setWillMapDeserializedResponseBlock:nil]; + return result; + }; + } +} + +- (void)setCompletionBlockWithSuccess:(void (^)(RKObjectRequestOperation *operation, RKMappingResult *mappingResult))success + failure:(void (^)(RKObjectRequestOperation *operation, NSError *error))failure +{ +// See above setCompletionBlock: +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warc-retain-cycles" + + //Keep blocks for copyWithZone + self.successBlock = success; + self.failureBlock = failure; + + self.completionBlock = ^ { + if ([self isCancelled] && !self.error) { + self.error = [NSError errorWithDomain:RKErrorDomain code:RKOperationCancelledError userInfo:nil]; + } + + if (self.error) { + if (failure) { + dispatch_async(self.failureCallbackQueue ?: dispatch_get_main_queue(), ^{ + failure(self, self.error); + }); + } + } else { + if (success) { + dispatch_async(self.successCallbackQueue ?: dispatch_get_main_queue(), ^{ + success(self, self.mappingResult); + }); + } + } + }; +#pragma clang diagnostic pop +} + +- (void)performMappingOnResponseWithCompletionBlock:(void(^)(RKMappingResult *mappingResult, NSError *error))completionBlock +{ + self.responseMapperOperation = [[RKObjectResponseMapperOperation alloc] initWithRequest:self.HTTPRequestOperation.request + response:self.HTTPRequestOperation.response + data:self.HTTPRequestOperation.responseData + responseDescriptors:self.responseDescriptors]; + self.responseMapperOperation.targetObject = self.targetObject; + self.responseMapperOperation.mappingMetadata = self.mappingMetadata; + self.responseMapperOperation.mapperDelegate = self; + [self.responseMapperOperation setQueuePriority:[self queuePriority]]; + [self.responseMapperOperation setWillMapDeserializedResponseBlock:self.willMapDeserializedResponseBlock]; + [self.responseMapperOperation setDidFinishMappingBlock:^(RKMappingResult *mappingResult, NSError *error) { + completionBlock(mappingResult, error); + }]; + [[RKObjectRequestOperation responseMappingQueue] addOperation:self.responseMapperOperation]; +} + +- (void)execute +{ + __weak __typeof(self)weakSelf = self; + + [self.HTTPRequestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) { + if (weakSelf.isCancelled) { + [weakSelf.stateMachine finish]; + return; + } + + weakSelf.mappingDidStartDate = [NSDate date]; + [weakSelf performMappingOnResponseWithCompletionBlock:^(RKMappingResult *mappingResult, NSError *error) { + if (weakSelf.isCancelled) { + [weakSelf.stateMachine finish]; + return; + } + + // If there is no mapping result but no error, there was no mapping to be performed, + // which we do not treat as an error condition + if (error && !([weakSelf.HTTPRequestOperation.request.HTTPMethod isEqualToString:@"DELETE"] && error.code == RKMappingErrorNotFound)) { + weakSelf.error = error; + [weakSelf.stateMachine finish]; + return; + } + weakSelf.mappingResult = mappingResult; + + if (weakSelf.error) { + weakSelf.mappingResult = nil; + } else { + NSCachedURLResponse *cachedResponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:weakSelf.HTTPRequestOperation.request]; + if (cachedResponse) { + // We're all done mapping this request. Now we set a flag on the cache entry's userInfo dictionary to indicate that the request + // corresponding to the cache entry completed successfully, and we can reliably skip mapping if a subsequent request results + // in the use of this cachedResponse. + NSMutableDictionary *userInfo = cachedResponse.userInfo ? [cachedResponse.userInfo mutableCopy] : [NSMutableDictionary dictionary]; + userInfo[RKResponseHasBeenMappedCacheUserInfoKey] = @YES; + NSCachedURLResponse *newCachedResponse = [[NSCachedURLResponse alloc] initWithResponse:cachedResponse.response data:cachedResponse.rkData userInfo:userInfo storagePolicy:cachedResponse.storagePolicy]; + [[NSURLCache sharedURLCache] storeCachedResponse:newCachedResponse forRequest:weakSelf.HTTPRequestOperation.request]; + } + } + + weakSelf.mappingDidFinishDate = [NSDate date]; + [weakSelf.stateMachine finish]; + }]; + } failure:^(AFHTTPRequestOperation *operation, NSError *error) { + RKLogError(@"Object request failed: Underlying HTTP request operation failed with error: %@", weakSelf.HTTPRequestOperation.error); + weakSelf.error = weakSelf.HTTPRequestOperation.error; + [weakSelf.stateMachine finish]; + }]; + + // Send the request + [self.HTTPRequestOperation start]; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"<%@: %p, state: %@, isCancelled=%@, request: %@, response: %@>", + NSStringFromClass([self class]), self, RKStringForStateOfObjectRequestOperation(self), [self isCancelled] ? @"YES" : @"NO", + self.HTTPRequestOperation.request, RKStringDescribingURLResponseWithData(self.HTTPRequestOperation.response, self.HTTPRequestOperation.responseData)]; +} + +- (void)willFinish +{ + // Default implementation does nothing +} + +#pragma mark - NSCopying + +- (id)copyWithZone:(NSZone *)zone { + RKObjectRequestOperation *operation = [(RKObjectRequestOperation *)[[self class] allocWithZone:zone] initWithHTTPRequestOperation:[self.HTTPRequestOperation copyWithZone:zone] responseDescriptors:self.responseDescriptors]; + operation.targetObject = self.targetObject; + operation.mappingMetadata = self.mappingMetadata; + operation.successCallbackQueue = self.successCallbackQueue; + operation.failureCallbackQueue = self.failureCallbackQueue; + operation.willMapDeserializedResponseBlock = self.willMapDeserializedResponseBlock; + [operation setCompletionBlockWithSuccess:self.successBlock failure:self.failureBlock]; + + return operation; +} + +#pragma mark - NSOperation + +- (BOOL)isConcurrent +{ + return YES; +} + +- (BOOL)isReady +{ + return [self.stateMachine isReady] && [super isReady]; +} + +- (BOOL)isExecuting +{ + return [self.stateMachine isExecuting]; +} + +- (BOOL)isFinished +{ + return [self.stateMachine isFinished]; +} + +- (void)start +{ + [self.stateMachine start]; +} + +- (void)cancel +{ + [super cancel]; + [self.stateMachine cancel]; +} + +@end + +#pragma mark - Fix for leak in iOS 5/6 "- [NSCachedURLResponse data]" message + +@implementation NSCachedURLResponse (RKLeakFix) + +- (NSData *)rkData +{ + @synchronized(self) { + NSData *result; + CFIndex count; + + @autoreleasepool { + result = [self data]; + count = CFGetRetainCount((__bridge CFTypeRef)result); + } + + if (CFGetRetainCount((__bridge CFTypeRef)result) == count) { +#ifndef __clang_analyzer__ + CFRelease((__bridge CFTypeRef)result); // Leak detected, manually release +#endif + } + + return result; + } +} + +@end diff --git a/Pods/RestKit/Code/Network/RKObjectRequestOperationSubclass.h b/Pods/RestKit/Code/Network/RKObjectRequestOperationSubclass.h new file mode 100644 index 0000000..284df50 --- /dev/null +++ b/Pods/RestKit/Code/Network/RKObjectRequestOperationSubclass.h @@ -0,0 +1,45 @@ +// +// RKObjectRequestOperationSubclass.h +// RestKit +// +// Created by Blake Watters on 9/16/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +/* + The extensions to the `RKObjectRequestOperation` class declared in the `ForSubclassEyesOnly` category are to be used by subclasses implementations only. Code that uses `RKObjectRequestOperation` objects must never call these methods. + */ +@interface RKObjectRequestOperation (ForSubclassEyesOnly) + +///---------------------------- +/// @name Subclassing Overrides +///---------------------------- + +/** + Performs object mapping using the `response` and `responseData` properties. + + The `RKObjectRequestOperation` superclass is responsible for the invocation of this method and the subsequent handling of the mapping result or error. + + @param error A pointer to an `NSError` object to be set in the event that the object mapping process has failed. + @return A mapping result or `nil` if an error has occurred. + */ +- (void)performMappingOnResponseWithCompletionBlock:(void(^)(RKMappingResult *mappingResult, NSError *error))completionBlock; + +/** + Invoked to tell the receiver that the object request operation is finishing its work and is about to transition into the finished state. Used to perform any necessary cleanup before the operation is finished. + */ +- (void)willFinish; + +@end diff --git a/Pods/RestKit/Code/Network/RKPaginator.h b/Pods/RestKit/Code/Network/RKPaginator.h new file mode 100644 index 0000000..32cda58 --- /dev/null +++ b/Pods/RestKit/Code/Network/RKPaginator.h @@ -0,0 +1,280 @@ +// +// RKPaginator.h +// RestKit +// +// Created by Blake Watters on 12/29/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKHTTPRequestOperation.h" +#import "RKObjectRequestOperation.h" +#import "RKObjectMapping.h" +#import "RKMappingResult.h" + +@protocol RKManagedObjectCaching; + +/** + Instances of `RKPaginator` retrieve paginated collections of mappable data from remote systems via HTTP. Paginators perform GET requests and use a patterned URL to construct a full URL reflecting the state of the paginator. Paginators rely on an instance of RKObjectMappingProvider to determine how to perform object mapping on the retrieved data. Paginators can load Core Data backed models provided that an instance of RKManagedObjectStore is assigned to the paginator. + + ## Configuring Pagination Mapping + + The paginator must be configured with a `paginationMapping` specifying how configuration metadata is to be mapped out of the response payload. The configured mapping must have an `objectClass` of `RKPaginator` and should include attribute mappings for the `currentPage`, `pageCount`, `perPage`, and `objectCount`. For example, given a paginated resource loaded from '/articles?page=1' with the followibg JSON: + + { "pagination": { "per_page": 10, "total_pages": 25, "total_objects": 250 }, "articles": [ // Array of articles ] } + + The pagination mapping would be configured as: + + RKObjectMapping *paginationMapping = [RKObjectMapping mappingForClass:[RKPaginator class]]; + [paginationMapping addAttributeMappingsFromDictionary:@{ + @"pagination.per_page": @"perPage", + @"pagination.total_pages": @"pageCount", + @"pagination.total_objects": @"objectCount", + }]; + + ## iOS 5 Compatibility Caveats + + The paginator is compatible with iOS 5.x through the use of proxy attributes. In iOS 6.0 and greater, key-value coding supports the automatic boxing and unboxing of primitive values. This enables direct mapping configuration for the `currentPage`, `pageCount`, `perPage`, and `objectCount` attributes. Under iOS 5, where autoboxing is not available, mapping configuration must target special proxy attributes instead. For each of the above properties, a private `NSNumber` property is implemented by the class. Each proxy property has 'Number' appended as a suffix to the property name: `currentPageNumber`, `pageCountNumber`, `perPageNumber`, and `objectCountNumber`. + + */ +@interface RKPaginator : NSObject + +///------------------------------------- +/// @name Initializing Paginator Objects +///------------------------------------- + +/** + Initializes a RKPaginator object with the a provided patternURL and mappingProvider. + + @param request A request with a URL containing a dynamic pattern specifying how paginated resources are to be accessed. + @param paginationMapping The pagination mapping specifying how pagination metadata is to be mapped from responses. + @param responseDescriptors An array of response descriptors describing how to map object representations loaded by object request operations dispatched by the paginator. + @return The receiver, initialized with the request, pagination mapping, and response descriptors. + */ +- (instancetype)initWithRequest:(NSURLRequest *)request + paginationMapping:(RKObjectMapping *)paginationMapping + responseDescriptors:(NSArray *)responseDescriptors NS_DESIGNATED_INITIALIZER; + +///----------------------------- +/// @name Configuring Networking +///----------------------------- + +/** + A URL with a path pattern for building a complete URL from + which to load the paginated resource collection. The patterned resource + path will be evaluated against the state of the paginator object itself. + + For example, given a paginated collection of data at the /articles path, + the path portion of the pattern URL may look like: + + /articles?per_page=:perPage&page_number=:currentPage + + When the pattern is evaluated against the state of the paginator, this will + yield a complete path that can be used to load the specified page. Given + a paginator configured with 100 objects per page and a current page number of 3, + the path portion of the pagination URL would become: + + /articles?per_page=100&page_number=3 + */ +@property (nonatomic, readonly) NSURL *patternURL; + +/** + Returns a complete URL to the paginated resource collection by interpolating the state of the paginator object against the patternURL. + */ +@property (nonatomic, readonly) NSURL *URL; + +/** + An optional operation queue on which object request operations constructed by the paginator are to be enqueued for processing. + */ +@property (nonatomic, strong) NSOperationQueue *operationQueue; + +/** + Returns the last object request operation used by the paginator to load a page of objects. + */ +@property (nonatomic, strong, readonly) RKObjectRequestOperation *objectRequestOperation; + +/** + Sets the `RKHTTPRequestOperation` subclass to be used when constructing HTTP request operations for requests dispatched by the paginator. + + **Default**: `[RKHTTPRequestOperation class]` + */ +- (void)setHTTPOperationClass:(Class)operationClass; + +///----------------------------------- +/// @name Setting the Completion Block +///----------------------------------- + +/** + Sets the completion block to be invoked when the paginator finishes loading a page of results. + + @param success A block to be executed upon a successful load of a page of objects. The block has no return value and takes three arguments: the paginator object, an array containing the paginated objects, and an integer indicating the page that was loaded. + @param failure A block to be exected upon a failed load. The block has no return value and takes two arguments: the paginator object and an error indicating the nature of the failure. + */ +- (void)setCompletionBlockWithSuccess:(void (^)(RKPaginator *paginator, NSArray *objects, NSUInteger page))success + failure:(void (^)(RKPaginator *paginator, NSError *error))failure; + + +///----------------------------------- +/// @name Accessing Pagination Results +///----------------------------------- + +/** + The mapping result containing the last set of paginated objects or `nil` if an error was encountered. + */ +@property (nonatomic, strong, readonly) RKMappingResult *mappingResult; + +/** + The error, if any, that occured during the last load of the paginator. + */ +@property (nonatomic, strong, readonly) NSError *error; + +///----------------------------------- +/// @name Object Mapping Configuration +///----------------------------------- + +/** + The object mapping defining how pagination metadata is to be mapped from a paginated response onto the paginator object. + + See the documentation in the "Configuring Pagination Mapping" section for details about the pagination mapping. + + @warning The `objectClass` of the given mapping must be `RKPaginator`. + */ +@property (nonatomic, strong) RKObjectMapping *paginationMapping; + +///------------------------------ +/// @name Core Data Configuration +///------------------------------ + +#ifdef _COREDATADEFINES_H +/** + The managed object context in which paginated managed objects are to be persisted. + */ +@property (nonatomic, strong) NSManagedObjectContext *managedObjectContext; + +/** + The managed object cache used to find existing managed object instances in the persistent store. + */ +@property (nonatomic, strong) id<RKManagedObjectCaching> managedObjectCache; + +/** + An array of fetch request blocks. + */ +@property (nonatomic, copy) NSArray *fetchRequestBlocks; +#endif + +///------------------------------------ +/// @name Accessing Pagination Metadata +///------------------------------------ + +/** + The number of objects to load per page + */ +@property (nonatomic, assign) NSUInteger perPage; + +/** + A Boolean value indicating if the paginator has loaded a page of objects + + @returns YES when the paginator has loaded a page of objects + */ +@property (nonatomic, readonly, getter = isLoaded) BOOL loaded; + +/** + Returns the page number for the most recently loaded page of objects. + + @return The page number for the current page of objects. + @exception NSInternalInconsistencyException Raised if `isLoaded` is equal to `NO`. + */ +@property (nonatomic, readonly) NSUInteger currentPage; + +/** + Returns the offset based off the page for the most recently loaded objects. + + @return The offset for the current page of objects. + @exception NSInternalInconsistencyException Raised if `isLoaded` is equal to `NO`. + */ +@property (nonatomic, readonly) NSUInteger offset; + +/** + Returns the number of pages in the total resource collection. + + @return A count of the number of pages in the resource collection. + @exception NSInternalInconsistencyException Raised if `hasPageCount` is `NO`. + */ +@property (nonatomic, readonly) NSUInteger pageCount; + +/** + Returns the total number of objects in the collection + + @return A count of the number of objects in the resource collection. + @exception NSInternalInconsistencyException Raised if `hasObjectCount` is `NO`. + */ +@property (nonatomic, readonly) NSUInteger objectCount; + +/** + Returns a Boolean value indicating if the total number of pages in the collection is known by the paginator. + + @return `YES` if the paginator knows the page count, otherwise `NO`. + */ +@property (nonatomic, readonly) BOOL hasPageCount; + +/** + Returns a Boolean value indicating if the total number of objects in the collection is known by the paginator. + + @return `YES` if the paginator knows the number of objects in the paginated collection, otherwise `NO`. + */ +@property (nonatomic, readonly) BOOL hasObjectCount; + +/** + Returns a Boolean value indicating if there is a next page in the collection. + + @return `YES` if there is a next page, otherwise `NO`. + @exception NSInternalInconsistencyException Raised if isLoaded or hasPageCount is `NO`. + */ +@property (nonatomic, readonly) BOOL hasNextPage; + +/** + Returns a Boolean value indicating if there is a previous page in the collection. + + @return `YES` if there is a previous page, otherwise `NO`. + @exception NSInternalInconsistencyException Raised if isLoaded is `NO`. + */ +@property (nonatomic, readonly) BOOL hasPreviousPage; + +///------------------------ +/// @name Paginator Actions +///------------------------ + +/** + Loads the next page of data by incrementing the current page, constructing an object loader to fetch the data, and object mapping the results. + */ +- (void)loadNextPage; + +/** + Loads the previous page of data by decrementing the current page, constructing an object loader to fetch the data, and object mapping the results. + */ +- (void)loadPreviousPage; + +/** + Loads a specific page of data by mutating the current page, constructing an object loader to fetch the data, and object mapping the results. + + @param pageNumber The page of objects to load from the remote backend + */ +- (void)loadPage:(NSUInteger)pageNumber; + +/** + Cancels an in-progress pagination request. + */ +- (void)cancel; + +@end diff --git a/Pods/RestKit/Code/Network/RKPaginator.m b/Pods/RestKit/Code/Network/RKPaginator.m new file mode 100644 index 0000000..f5ef61d --- /dev/null +++ b/Pods/RestKit/Code/Network/RKPaginator.m @@ -0,0 +1,329 @@ +// +// RKPaginator.m +// RestKit +// +// Created by Blake Watters on 12/29/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKPaginator.h" +#import "RKMappingOperation.h" +#import "SOCKit.h" +#import "RKLog.h" +#import "RKPathMatcher.h" +#import "RKHTTPUtilities.h" + +#ifdef _COREDATADEFINES_H +#if __has_include("RKCoreData.h") +#define RKCoreDataIncluded +#import "RKManagedObjectRequestOperation.h" +#endif +#endif + +static NSUInteger RKPaginatorDefaultPerPage = 25; + +// Private interface +@interface RKPaginator () +@property (nonatomic, copy) NSURLRequest *request; +@property (nonatomic, strong) Class HTTPOperationClass; +@property (nonatomic, copy) NSArray *responseDescriptors; +@property (nonatomic, assign, readwrite) NSUInteger currentPage; +@property (nonatomic, assign, readwrite) NSUInteger offset; +@property (nonatomic, assign, readwrite) NSUInteger pageCount; +@property (nonatomic, assign, readwrite) NSUInteger objectCount; +@property (nonatomic, assign, readwrite) BOOL loaded; +@property (nonatomic, strong, readwrite) RKMappingResult *mappingResult; +@property (nonatomic, strong, readwrite) NSError *error; +@property (nonatomic, strong, readwrite) RKObjectRequestOperation *objectRequestOperation; + +// iOS 5.x compatible proxy attributes +@property (nonatomic, assign, readwrite) NSNumber *perPageNumber; +@property (nonatomic, assign, readwrite) NSNumber *currentPageNumber; +@property (nonatomic, assign, readwrite) NSNumber *pageCountNumber; +@property (nonatomic, assign, readwrite) NSNumber *objectCountNumber; + +@property (nonatomic, copy) void (^successBlock)(RKPaginator *paginator, NSArray *objects, NSUInteger page); +@property (nonatomic, copy) void (^failureBlock)(RKPaginator *paginator, NSError *error); +@end + +@implementation RKPaginator + +- (instancetype)initWithRequest:(NSURLRequest *)request + paginationMapping:(RKObjectMapping *)paginationMapping + responseDescriptors:(NSArray *)responseDescriptors; +{ + NSParameterAssert(request); + NSParameterAssert(paginationMapping); + NSParameterAssert(responseDescriptors); + NSAssert([paginationMapping.objectClass isSubclassOfClass:[RKPaginator class]], @"The paginationMapping must have a target object class of `RKPaginator`"); + self = [super init]; + if (self) { + self.HTTPOperationClass = [RKHTTPRequestOperation class]; + self.request = request; + self.paginationMapping = paginationMapping; + self.responseDescriptors = responseDescriptors; + self.currentPage = NSNotFound; + self.pageCount = NSNotFound; + self.objectCount = NSNotFound; + self.offset = NSNotFound; + self.perPage = RKPaginatorDefaultPerPage; + self.loaded = NO; + } + + return self; +} + +- (void)dealloc +{ + [self.objectRequestOperation cancel]; +} + +- (NSURL *)patternURL +{ + return self.request.URL; +} + +- (NSURL *)URL +{ + NSString *pathAndQueryString = RKPathAndQueryStringFromURLRelativeToURL(self.patternURL, nil); + NSString *interpolatedString = RKPathFromPatternWithObject(pathAndQueryString, self); + return [NSURL URLWithString:interpolatedString relativeToURL:self.request.URL]; +} + +- (void)setHTTPOperationClass:(Class)operationClass +{ + NSAssert(operationClass == nil || [operationClass isSubclassOfClass:[RKHTTPRequestOperation class]], @"The HTTP operation class must be a subclass of `RKHTTPRequestOperation`"); + _HTTPOperationClass = operationClass; +} + +- (void)setCompletionBlockWithSuccess:(void (^)(RKPaginator *paginator, NSArray *objects, NSUInteger page))success + failure:(void (^)(RKPaginator *paginator, NSError *error))failure +{ + self.successBlock = success; + self.failureBlock = failure; +} + +// Private. Public consumers can rely on isLoaded +- (BOOL)hasCurrentPage +{ + return _currentPage != NSNotFound; +} + +- (BOOL)hasOffset +{ + return _offset != NSNotFound; +} + +- (BOOL)hasPageCount +{ + return _pageCount != NSNotFound; +} + +- (BOOL)hasObjectCount +{ + return _objectCount != NSNotFound; +} + +- (NSUInteger)currentPage +{ + // Referenced during initial load, so we don't rely on isLoaded. + NSAssert([self hasCurrentPage], @"Current page has not been initialized."); + return _currentPage; +} + +- (NSUInteger)offset +{ + if ([self hasOffset]) return _offset; + return [self hasCurrentPage] ? ((_currentPage - 1) * _perPage) : 0; +} + +- (BOOL)hasNextPage +{ + NSAssert(self.isLoaded, @"Cannot determine hasNextPage: paginator is not loaded."); + NSAssert([self hasPageCount], @"Cannot determine hasNextPage: page count is not known."); + + return self.currentPage < self.pageCount; +} + +- (BOOL)hasPreviousPage +{ + NSAssert(self.isLoaded, @"Cannot determine hasPreviousPage: paginator is not loaded."); + return self.currentPage > 1; +} + +#pragma mark - Action methods + +- (void)loadNextPage +{ + [self loadPage:self.currentPage + 1]; +} + +- (void)loadPreviousPage +{ + [self loadPage:self.currentPage - 1]; +} + +- (void)loadPage:(NSUInteger)pageNumber +{ + if (self.objectRequestOperation.HTTPRequestOperation.response) { + // The user by calling loadPage is ready to perform the next request so invalidate objectRequestOperation + self.objectRequestOperation = nil; + } + + NSAssert(self.responseDescriptors, @"Cannot perform a load with nil response descriptors."); + NSAssert(! self.objectRequestOperation, @"Cannot perform a load while one is already in progress."); + self.currentPage = pageNumber; + + NSMutableURLRequest *mutableRequest = [self.request mutableCopy]; + mutableRequest.URL = self.URL; + +#ifdef RKCoreDataIncluded + if (self.managedObjectContext) { + RKHTTPRequestOperation *requestOperation = [[self.HTTPOperationClass alloc] initWithRequest:mutableRequest]; + RKManagedObjectRequestOperation *managedObjectRequestOperation = [[RKManagedObjectRequestOperation alloc] initWithHTTPRequestOperation:requestOperation responseDescriptors:self.responseDescriptors]; + managedObjectRequestOperation.managedObjectContext = self.managedObjectContext; + managedObjectRequestOperation.managedObjectCache = self.managedObjectCache; + managedObjectRequestOperation.fetchRequestBlocks = self.fetchRequestBlocks; + managedObjectRequestOperation.deletesOrphanedObjects = NO; + + self.objectRequestOperation = managedObjectRequestOperation; + } else { + self.objectRequestOperation = [[RKObjectRequestOperation alloc] initWithRequest:mutableRequest responseDescriptors:self.responseDescriptors]; + } +#else + self.objectRequestOperation = [[RKObjectRequestOperation alloc] initWithRequest:mutableRequest responseDescriptors:self.responseDescriptors]; +#endif + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warc-retain-cycles" + [self.objectRequestOperation setWillMapDeserializedResponseBlock:^id(id deserializedResponseBody) { + NSError *error = nil; + RKMappingOperation *mappingOperation = [[RKMappingOperation alloc] initWithSourceObject:deserializedResponseBody destinationObject:self mapping:self.paginationMapping]; + BOOL success = [mappingOperation performMapping:&error]; + if (!success) { + self.pageCount = 0; + self.currentPage = 0; + RKLogError(@"Paginator didn't map info to compute page count. Assuming no pages."); + } else if (self.perPage && [self hasObjectCount]) { + float objectCountFloat = self.objectCount; + self.pageCount = ceilf(objectCountFloat / self.perPage); + RKLogInfo(@"Paginator objectCount: %ld pageCount: %ld", (long)self.objectCount, (long)self.pageCount); + } else { + RKLogError(@"Paginator perPage set is 0."); + } + + return deserializedResponseBody; + }]; + [self.objectRequestOperation setCompletionBlockWithSuccess:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) { + [self finish]; + if (self.successBlock) { + self.successBlock(self, [mappingResult array], self.currentPage); + } + } failure:^(RKObjectRequestOperation *operation, NSError *error) { + [self finish]; + if (self.failureBlock) { + self.failureBlock(self, error); + } + }]; +#pragma clang diagnostic pop + + if (self.operationQueue) { + [self.operationQueue addOperation:self.objectRequestOperation]; + } else { + [self.objectRequestOperation start]; + } +} + +- (void)waitUntilFinished +{ + [self.objectRequestOperation waitUntilFinished]; +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@"<%@: %p patternURL=%@ isLoaded=%@ perPage=%ld currentPage=%@ offset=%@ pageCount=%@ objectCount=%@>", + NSStringFromClass([self class]), self, self.patternURL, self.isLoaded ? @"YES" : @"NO", (long) self.perPage, + [self hasCurrentPage] ? @(self.currentPage) : @"???", + [self hasOffset] ? @(self.offset) : @"???", + [self hasPageCount] ? @(self.pageCount) : @"???", + [self hasObjectCount] ? @(self.objectCount) : @"???"]; +} + +- (void)finish +{ + self.loaded = (self.objectRequestOperation.mappingResult != nil); + self.mappingResult = self.objectRequestOperation.mappingResult; + self.error = self.objectRequestOperation.error; +} + +- (void)cancel +{ + [self.objectRequestOperation cancel]; + self.objectRequestOperation = nil; +} + +#pragma mark - iOS 5 proxy attributes + +- (NSNumber *)perPageNumber +{ + return @(self.perPage); +} + +- (void)setPerPageNumber:(NSNumber *)perPageNumber +{ + self.perPage = [perPageNumber unsignedIntegerValue]; +} + +- (NSNumber *)currentPageNumber +{ + return @(self.currentPage); +} + +- (void)setCurrentPageNumber:(NSNumber *)currentPageNumber +{ + self.currentPage = [currentPageNumber unsignedIntegerValue]; +} + +- (NSNumber *)pageCountNumber +{ + return @(self.pageCount); +} + +- (void)setPageCountNumber:(NSNumber *)pageCountNumber +{ + self.pageCount = [pageCountNumber unsignedIntegerValue]; +} + +- (NSNumber *)objectCountNumber +{ + return @(self.objectCount); +} + +- (void)setObjectCountNumber:(NSNumber *)objectCountNumber +{ + self.objectCount = [objectCountNumber unsignedIntegerValue]; +} + +- (NSNumber *)offsetNumber +{ + return @(self.offset); +} + +- (void)setOffsetNumber:(NSNumber *)offsetNumber +{ + self.offset = [offsetNumber unsignedIntegerValue]; +} + +@end diff --git a/Pods/RestKit/Code/Network/RKPathMatcher.h b/Pods/RestKit/Code/Network/RKPathMatcher.h new file mode 100644 index 0000000..fb1cee9 --- /dev/null +++ b/Pods/RestKit/Code/Network/RKPathMatcher.h @@ -0,0 +1,132 @@ +// +// RKPathMatcher.h +// RestKit +// +// Created by Greg Combs on 9/2/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import <Foundation/Foundation.h> +@class SOCPattern; + +/** + Convenience method for generating a path against the properties of an object. Takes an `NSString` with property names prefixed with a colon and interpolates the values of the properties specified and returns the generated path. + + For example, given an `article` object with an `articleID` property whose value is `@12345`, `RKPathFromPatternWithObject(@"articles/:articleID", article)` would return `@"articles/12345"`. + + This functionality is the basis for path generation in the `RKRouter` class. + + @param pathPattern An `SOCPattern` string containing zero or more colon-prefixed property names. + @param object The object to interpolate the properties against + @return A new `NSString` object with the values of the given object interpolated for the colon-prefixed properties name in the given pattern string. + @see `RKPathMatcher` + @see `SOCPattern` + */ +NSString *RKPathFromPatternWithObject(NSString *pathPattern, id object); + +/** + The `RKPathMatcher` class performs pattern matching and parameter parsing of strings, typically representing the path portion of an `NSURL` object. It provides much of the necessary tools to map a given path to local objects (the inverse of RKRouter's function). This makes it easier to implement the `RKManagedObjectCaching` protocol and generate `NSFetchRequest` objects from a given path. There are two means of instantiating and using a matcher object in order to provide more flexibility in implementations, and to improve efficiency by eliminating repetitive and costly pattern initializations. + + @see `RKManagedObjectCaching` + @see `RKPathFromPatternWithObject` + @see `RKRouter` + */ +@interface RKPathMatcher : NSObject <NSCopying> + +///--------------------------------- +/// @name Matching Paths to Patterns +///--------------------------------- + +/** + Creates a path match object starting from a path string. This method should be followed by `matchesPattern:tokenizeQueryStrings:parsedArguments:` + + @param pathString The string to evaluate and parse, such as `/districts/tx/upper/?apikey=GC5512354` + @return An instantiated `RKPathMatcher` without an established pattern. + */ ++ (instancetype)pathMatcherWithPath:(NSString *)pathString; + +/** + Determines if the path string matches the provided pattern, and yields a dictionary with the resulting matched key/value pairs. Use of this method should be preceded by `pathMatcherWithPath:` Pattern strings should include encoded parameter keys, delimited by a single colon at the beginning of the key name. + + *NOTE 1 *- Numerous colon-encoded parameter keys can be joined in a long pattern, but each key must be separated by at least one unmapped character. For instance, `/:key1:key2:key3/` is invalid, whereas `/:key1/:key2/:key3/` is acceptable. + + *NOTE 2 *- The pattern matcher supports KVM, so `:key1.otherKey` normally resolves as it would in any other KVM + situation, ... otherKey is a sub-key on a the object represented by key1. This presents problems in circumstances where + you might want to build a pattern like /:filename.json, where the dot isn't intended as a sub-key on the filename, but rather + part of the json static string. In these instances, you need to escape the dot with two backslashes, like so: + /:filename\\.json + + @param patternString The pattern to use for evaluating, such as `/:entityName/:stateID/:chamber/` + @param shouldTokenize If YES, any query parameters will be tokenized and inserted into the parsed argument dictionary. + @param arguments A pointer to a dictionary that contains the key/values from the pattern (and parameter) matching. + @return A boolean value indicating if the path string successfully matched the pattern. + */ +- (BOOL)matchesPattern:(NSString *)patternString tokenizeQueryStrings:(BOOL)shouldTokenize parsedArguments:(NSDictionary **)arguments; + +///--------------------------------- +/// @name Matching Patterns to Paths +///--------------------------------- + +/** + Creates a path matcher object starting from a pattern string. This method should be followed by `matchesPath:tokenizeQueryStrings:parsedArguments:`. Patterns should include encoded parameter keys, delimited by a single colon at the beginning of the key name. + + *NOTE 1 *- Numerous colon-encoded parameter keys can be joined in a long pattern, but each key must be separated by at least one unmapped character. For instance, `/:key1:key2:key3/` is invalid, whereas `/:key1/:key2/:key3/` is acceptable. + + *NOTE 2 *- The pattern matcher supports KVM, so `:key1.otherKey` normally resolves as it would in any other KVM situation, ... otherKey is a sub-key on a the object represented by key1. This presents problems in circumstances where you might want to build a pattern like `/:filename.json`, where the dot isn't intended as a sub-key on the filename, but rather part of the json static string. In these instances, you need to escape the dot with two backslashes, like so: `/:filename\\.json` + + @param patternString The pattern to use for evaluating, such as `/:entityName/:stateID/:chamber/` + @return An instantiated `RKPathMatcher` with an established pattern. + */ ++ (instancetype)pathMatcherWithPattern:(NSString *)patternString; + +/** + Determines if the given path string matches a pattern, and yields a dictionary with the resulting matched key/value pairs. Use of this method should be preceded by `pathMatcherWithPattern:`. + + @param pathString The string to evaluate and parse, such as `/districts/tx/upper/?apikey=GC5512354` + @param shouldTokenize If YES, any query parameters will be tokenized and inserted into the parsed argument dictionary. + @param arguments A pointer to a dictionary that contains the key/values from the pattern (and parameter) matching. + @return A boolean value indicating if the path string successfully matched the pattern. + */ +- (BOOL)matchesPath:(NSString *)pathString tokenizeQueryStrings:(BOOL)shouldTokenize parsedArguments:(NSDictionary **)arguments; + +///---------------------------------- +/// @name Creating Paths from Objects +///---------------------------------- + +/** + Generates a path by interpolating the properties of the 'object' argument, assuming the existence of a previously specified pattern established via `pathMatcherWithPattern:`. Otherwise, this method is identical in function to `RKPathFromPatternWithObject` (in fact it is a shortcut for this method). + + For example, given an 'article' object with an 'articleID' property value of 12345 and a code of "This/That"... + + RKPathMatcher *matcher = [RKPathMatcher pathMatcherWithPattern:@"/articles/:articleID/:code"]; + NSString *path = [matcher pathFromObject:article addingEscapes:YES interpolatedParameters:nil]; + + ... will produce a 'path' containing the string `@"/articles/12345/This%2FThat"` + + @param object The object containing the properties to interpolate. + @param addEscapes Conditionally add percent escapes to the interpolated property values + @param interpolatedParameters On input, a pointer for a dictionary object. When the path pattern of the receiver is interpolated, this pointer is set to a new dictionary object in which the keys correspond to the named parameters within the path pattern and the values are taken from the corresponding keypaths of the interpolated object . + @return A string with the object's interpolated property values inserted into the receiver's established pattern. + @see `RKRouter` + */ +- (NSString *)pathFromObject:(id)object addingEscapes:(BOOL)addEscapes interpolatedParameters:(NSDictionary **)interpolatedParameters; + +///------------------------------------------- +/// @name Accessing Tokenized Query Parameters +///------------------------------------------- + +@property (copy, readonly) NSDictionary *queryParameters; + +@end diff --git a/Pods/RestKit/Code/Network/RKPathMatcher.m b/Pods/RestKit/Code/Network/RKPathMatcher.m new file mode 100644 index 0000000..a8ce9bc --- /dev/null +++ b/Pods/RestKit/Code/Network/RKPathMatcher.m @@ -0,0 +1,154 @@ +// +// RKPathMatcher.m +// RestKit +// +// Created by Greg Combs on 9/2/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKPathMatcher.h" +#import "SOCKit.h" +#import "RKLog.h" +#import "RKDictionaryUtilities.h" + +static NSString *RKEncodeURLString(NSString *unencodedString); +extern NSDictionary *RKQueryParametersFromStringWithEncoding(NSString *string, NSStringEncoding stringEncoding); + +// NSString's stringByAddingPercentEscapes doesn't do a complete job (it ignores "/?&", among others) +static NSString *RKEncodeURLString(NSString *unencodedString) +{ + NSString *encodedString = (NSString *)CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes( + NULL, + (__bridge CFStringRef)unencodedString, + NULL, + (CFStringRef)@"!*'();:@&=+$,/?%#[]", + kCFStringEncodingUTF8)); + return encodedString; +} + +static NSUInteger RKNumberOfSlashesInString(NSString *string) +{ + static NSRegularExpression *regex = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + regex = [NSRegularExpression regularExpressionWithPattern:@"/" options:NSRegularExpressionCaseInsensitive error:nil]; + }); + return [regex numberOfMatchesInString:string options:0 range:NSMakeRange(0, [string length])]; +} + +NSString *RKPathFromPatternWithObject(NSString *pathPattern, id object) +{ + NSCAssert(object != NULL, @"Object provided is invalid; cannot create a path from a NULL object"); + RKPathMatcher *matcher = [RKPathMatcher pathMatcherWithPattern:pathPattern]; + return [matcher pathFromObject:object addingEscapes:NO interpolatedParameters:nil]; +} + +@interface RKPathMatcher () +@property (nonatomic, strong) SOCPattern *socPattern; +@property (nonatomic, copy) NSString *patternString; // SOCPattern keeps it private +@property (nonatomic, copy) NSString *sourcePath; +@end + +@implementation RKPathMatcher + +- (id)copyWithZone:(NSZone *)zone +{ + RKPathMatcher *copy = [[[self class] allocWithZone:zone] init]; + copy.socPattern = self.socPattern; + copy.patternString = self.patternString; + copy.sourcePath = self.sourcePath; + return copy; +} + ++ (instancetype)pathMatcherWithPattern:(NSString *)patternString +{ + NSAssert(patternString != NULL, @"Pattern string must not be empty in order to perform pattern matching."); + RKPathMatcher *matcher = [self new]; + matcher.socPattern = [SOCPattern patternWithString:patternString]; + matcher.patternString = patternString; + return matcher; +} + ++ (instancetype)pathMatcherWithPath:(NSString *)pathString +{ + RKPathMatcher *matcher = [self new]; + matcher.sourcePath = pathString; + return matcher; +} + +- (BOOL)itMatchesAndHasParsedArguments:(NSDictionary **)arguments andPattern:(NSString*)pattern andSourcePath:(NSString*)sourcePath tokenizeQueryStrings:(BOOL)shouldTokenize +{ + NSMutableDictionary *argumentsCollection = [NSMutableDictionary dictionary]; + NSString *rootPath = [sourcePath copy]; + NSArray *components = [sourcePath componentsSeparatedByString:@"?"]; + SOCPattern *socPattern = [SOCPattern patternWithString:pattern]; + + // Bifurcate Source Path From Query Parameters + + if ([components count] > 1) { + rootPath = [components objectAtIndex:0]; + NSDictionary *queryParameters = RKQueryParametersFromStringWithEncoding([components objectAtIndex:1], NSUTF8StringEncoding); + if (shouldTokenize) { + [argumentsCollection addEntriesFromDictionary:queryParameters]; + } + } + + bool rootPathMatchesPattern = RKNumberOfSlashesInString(pattern) == RKNumberOfSlashesInString(rootPath); + + if (![socPattern stringMatches:rootPath]) return NO; + if (!arguments) return YES && rootPathMatchesPattern; + NSDictionary *extracted = [socPattern parameterDictionaryFromSourceString:rootPath]; + if (extracted) [argumentsCollection addEntriesFromDictionary:RKDictionaryByReplacingPercentEscapesInEntriesFromDictionary(extracted)]; + *arguments = argumentsCollection; + return YES && rootPathMatchesPattern; +} + +- (BOOL)matchesPattern:(NSString *)patternString tokenizeQueryStrings:(BOOL)shouldTokenize parsedArguments:(NSDictionary **)arguments +{ + NSAssert(self.sourcePath != NULL, @"Matcher is not configured correctly. Instantiate it using pathMatcherWithPath: to use matchesPattern:tokenizeQueryStrings:parsedArguments"); + NSAssert(patternString != NULL, @"Pattern string must not be empty in order to perform patterm matching."); + return [self itMatchesAndHasParsedArguments:arguments andPattern:patternString andSourcePath:self.sourcePath tokenizeQueryStrings:shouldTokenize]; +} + +- (BOOL)matchesPath:(NSString *)sourceString tokenizeQueryStrings:(BOOL)shouldTokenize parsedArguments:(NSDictionary **)arguments +{ + return [self itMatchesAndHasParsedArguments:arguments andPattern:self.patternString andSourcePath:sourceString tokenizeQueryStrings:shouldTokenize]; +} + +- (NSString *)pathFromObject:(id)object addingEscapes:(BOOL)addEscapes interpolatedParameters:(NSDictionary **)interpolatedParameters +{ + NSAssert(self.socPattern != NULL, @"Matcher has no established pattern. Instantiate it using pathMatcherWithPattern: before calling pathFromObject:"); + NSAssert(object != NULL, @"Object provided is invalid; cannot create a path from a NULL object"); + NSString *(^encoderBlock)(NSString *interpolatedString) = nil; + if (addEscapes) { + encoderBlock = ^NSString *(NSString *interpolatedString) { + return RKEncodeURLString(interpolatedString); + }; + } + NSString *path = [self.socPattern stringFromObject:object withBlock:encoderBlock]; + if (interpolatedParameters) { + NSMutableDictionary *parsedParameters = [[self.socPattern parameterDictionaryFromSourceString:path] mutableCopy]; + if (addEscapes) { + for (NSString *key in [parsedParameters allKeys]) { + NSString *unescapedParameter = [parsedParameters[key] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; + [parsedParameters setValue:unescapedParameter forKey:key]; + } + } + *interpolatedParameters = parsedParameters; + } + return path; +} + +@end diff --git a/Pods/RestKit/Code/Network/RKRequestDescriptor.h b/Pods/RestKit/Code/Network/RKRequestDescriptor.h new file mode 100644 index 0000000..3b45e17 --- /dev/null +++ b/Pods/RestKit/Code/Network/RKRequestDescriptor.h @@ -0,0 +1,110 @@ +// +// RKRequestDescriptor.h +// RestKit +// +// Created by Blake Watters on 8/24/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import <Foundation/Foundation.h> +#import "RKHTTPUtilities.h" + +@class RKMapping; + +/** + An `RKRequestDescriptor` object describes an object mapping configuration that is used to construct the parameters of an HTTP request for an object. Request descriptors are defined by specifying the `RKMapping` object (whose `objectClass` must be `NSMutableDictionary`) that is to be used when object mapping an object into an `NSDictionary` of parameters, the class of the type of object for which the mapping is to be applied, and an optional root key path under which the paramters are to be nested. Response descriptors are only utilized when construct parameters for an `NSURLRequest` with an HTTP method of `POST`, `PUT`, or `PATCH`. + + @see RKObjectParameterization + @see [RKObjectMapping requestMapping] + @see [RKObjectManager requestWithObject:method:path:parameters:] + */ +@interface RKRequestDescriptor : NSObject + +///------------------------------------ +/// @name Creating a Request Descriptor +///------------------------------------ + +/** + Creates and returns a new `RKRequestDescriptor` object. + + This method is deprecated. Use `+ (instancetype)requestDescriptorWithMapping:(RKMapping *)mapping + objectClass:(Class)objectClass + rootKeyPath:(NSString *)rootKeyPath + method:(RKRequestMethod)method` instead. + + @param mapping The mapping to be used when parameterizing an object using the request descriptor. Cannot be nil and must have an objectClass equal to `[NSMutableDictionary class]`. + @param objectClass The class of objects for which the request descriptor should be used. Cannot be nil. + @param rootKeyPath The root key path under which paramters constructed using the response descriptor will be nested. If nil, the parameters will not be nested and returned as a flat dictionary object. + @return A new `RKRequestDescriptor` object. + + @see [RKObjectMapping requestMapping] + @warning An exception will be raised if the objectClass of the given mapping is not `[NSMutableDictionary class]`. + */ ++ (instancetype)requestDescriptorWithMapping:(RKMapping *)mapping + objectClass:(Class)objectClass + rootKeyPath:(NSString *)rootKeyPath DEPRECATED_ATTRIBUTE; + +/** +Creates and returns a new `RKRequestDescriptor` object. + +@param mapping The mapping to be used when parameterizing an object using the request descriptor. Cannot be nil and must have an objectClass equal to `[NSMutableDictionary class]`. +@param objectClass The class of objects for which the request descriptor should be used. Cannot be nil. +@param rootKeyPath The root key path under which paramters constructed using the response descriptor will be nested. If nil, the parameters will not be nested and returned as a flat dictionary object. +@param method The HTTP method(s) for which the mapping is to be used. +@return A new `RKRequestDescriptor` object. + +@see [RKObjectMapping requestMapping] +@warning An exception will be raised if the objectClass of the given mapping is not `[NSMutableDictionary class]`. +*/ ++ (instancetype)requestDescriptorWithMapping:(RKMapping *)mapping + objectClass:(Class)objectClass + rootKeyPath:(NSString *)rootKeyPath + method:(RKRequestMethod)method; + +///----------------------------------------------------- +/// @name Getting Information About a Request Descriptor +///----------------------------------------------------- + +/** + The mapping specifying how the object being parameterized is to be mapped into an `NSDictionary` representation. The mapping must have an objectClass equal to `[NSMutableDictionary class]`. + */ +@property (nonatomic, strong, readonly) RKMapping *mapping; + +/** + The class of objects that the request descriptor is appropriate for use in parameterizing. + */ +@property (nonatomic, strong, readonly) Class objectClass; + +/** + The root key path that the paramters for the object are to be nested under. May be nil. + */ +@property (nonatomic, copy, readonly) NSString *rootKeyPath; + +/** + The HTTP method(s) for which the mapping is to be used. + */ +@property (nonatomic, assign, readonly) RKRequestMethod method; + +///------------------------- +/// @name Comparing Request Descriptors +///------------------------- + +/** + Returns `YES` if the receiver and the specified request descriptor are considered equivalent. + + */ +- (BOOL)isEqualToRequestDescriptor:(RKRequestDescriptor *)otherDescriptor; + +@end diff --git a/Pods/RestKit/Code/Network/RKRequestDescriptor.m b/Pods/RestKit/Code/Network/RKRequestDescriptor.m new file mode 100644 index 0000000..0a1ddd5 --- /dev/null +++ b/Pods/RestKit/Code/Network/RKRequestDescriptor.m @@ -0,0 +1,118 @@ +// +// RKRequestDescriptor.m +// RestKit +// +// Created by Blake Watters on 8/24/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Created by Blake Watters on 8/24/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKRequestDescriptor.h" +#import "RKObjectMapping.h" +#import "RKDynamicMapping.h" + +static void RKAssertValidMappingForRequestDescriptor(RKMapping *mapping) +{ + if ([mapping isKindOfClass:[RKObjectMapping class]]) { + if (! [[(RKObjectMapping *)mapping objectClass] isEqual:[NSMutableDictionary class]]) { + [NSException raise:NSInvalidArgumentException format:@"`RKRequestDescriptor` objects must be initialized with a mapping whose target class is `NSMutableDictionary`, got '%@' (see `[RKObjectMapping requestMapping]`)", [(RKObjectMapping *)mapping objectClass]]; + } + } else if ([mapping isKindOfClass:[RKDynamicMapping class]]) { + [[(RKDynamicMapping *)mapping objectMappings] enumerateObjectsUsingBlock:^(RKObjectMapping *objectMapping, NSUInteger idx, BOOL *stop) { + if (! [objectMapping.objectClass isEqual:[NSMutableDictionary class]]) { + [NSException raise:NSInvalidArgumentException format:@"`RKRequestDescriptor` objects may only be initialized with `RKDynamicMapping` objects containing `RKObjectMapping` objects whose target class is `NSMutableDictionary`, got '%@' (see `[RKObjectMapping requestMapping]`)", objectMapping.objectClass]; + } + }]; + } else { + [NSException raise:NSInvalidArgumentException format:@"Expected an instance of `RKObjectMapping` or `RKDynamicMapping`, instead got '%@'", [mapping class]]; + } +} + +extern NSString *RKStringDescribingRequestMethod(RKRequestMethod method); + +@interface RKRequestDescriptor () + +@property (nonatomic, strong, readwrite) RKMapping *mapping; +@property (nonatomic, strong, readwrite) Class objectClass; +@property (nonatomic, copy, readwrite) NSString *rootKeyPath; +@property (nonatomic, assign, readwrite) RKRequestMethod method; + +@end + +@implementation RKRequestDescriptor + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-implementations" ++ (instancetype)requestDescriptorWithMapping:(RKMapping *)mapping objectClass:(Class)objectClass rootKeyPath:(NSString *)rootKeyPath +{ + return [self requestDescriptorWithMapping:mapping objectClass:objectClass rootKeyPath:rootKeyPath method:RKRequestMethodAny]; +} +#pragma clang diagnostic pop + ++ (instancetype)requestDescriptorWithMapping:(RKMapping *)mapping objectClass:(Class)objectClass rootKeyPath:(NSString *)rootKeyPath method:(RKRequestMethod)method +{ + NSParameterAssert(mapping); + NSParameterAssert(objectClass); + RKAssertValidMappingForRequestDescriptor(mapping); + + RKRequestDescriptor *requestDescriptor = [self new]; + requestDescriptor.mapping = mapping; + requestDescriptor.objectClass = objectClass; + requestDescriptor.rootKeyPath = rootKeyPath; + requestDescriptor.method = method; + return requestDescriptor; +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@"<%@: %p method=%@ objectClass=%@ rootKeyPath=%@ : %@>", + NSStringFromClass([self class]), self, RKStringDescribingRequestMethod(self.method), NSStringFromClass(self.objectClass), self.rootKeyPath, self.mapping]; +} + +- (BOOL)isEqual:(id)object +{ + if (self == object) { + return YES; + } + if ([self class] != [object class]) { + return NO; + } + return [self isEqualToRequestDescriptor:object]; +} + +#define NSUINT_BIT (CHAR_BIT * sizeof(NSUInteger)) +#define NSUINTROTATE(val, howmuch) ((((NSUInteger)val) << howmuch) | (((NSUInteger)val) >> (NSUINT_BIT - howmuch))) + +- (NSUInteger)hash +{ + return NSUINTROTATE(NSUINTROTATE([self.mapping hash], NSUINT_BIT / 3) ^ [self.objectClass hash], NSUINT_BIT / 3) ^ [self.rootKeyPath hash]; +} + +- (BOOL)isEqualToRequestDescriptor:(RKRequestDescriptor *)otherDescriptor +{ + if (![otherDescriptor isKindOfClass:[RKRequestDescriptor class]]) { + return NO; + } + + return + [self.mapping isEqualToMapping:otherDescriptor.mapping] && + self.objectClass == otherDescriptor.objectClass && + self.method == otherDescriptor.method && + ((self.rootKeyPath == otherDescriptor.rootKeyPath) || [self.rootKeyPath isEqualToString:otherDescriptor.rootKeyPath]); +} + +@end diff --git a/Pods/RestKit/Code/Network/RKResponseDescriptor.h b/Pods/RestKit/Code/Network/RKResponseDescriptor.h new file mode 100644 index 0000000..d2d9928 --- /dev/null +++ b/Pods/RestKit/Code/Network/RKResponseDescriptor.h @@ -0,0 +1,181 @@ +// +// RKResponseDescriptor.h +// RestKit +// +// Created by Blake Watters on 8/16/12. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKHTTPUtilities.h" + +@class RKMapping; + +/** + An `RKResponseDescriptor` object describes an object mapping configuration that is applicable to an HTTP response. Response descriptors are defined by specifying the `RKMapping` object that is to be used when performing object mapping on the deserialized response body and the URL path pattern, key path, and status codes for which the mapping is appropriate. The path pattern is a SOCKit `SOCPattern` string that will be matched against the URL of the request that loaded the response being mapped. If the path pattern is nil, the response descriptor is considered to be appropriate for a response loaded from any URL. The key path specifies the location of data within the deserialized response body for which the mapping is appropriate. If nil, the mapping is considered to apply to the entire response body. The status codes specify a set of HTTP response status codes for which the mapping is appropriate. It is common to constrain a response descriptor to the HTTP Successful status code class (status codes in the 200-299 range). Object mapping for error responses can be configured by configuring a response descriptor to handle the Client Error status code class (status codes in the 400-499 range). Instances of `RKResponseDescriptor` are immutable. + + @see RKPathMatcher + @see RKStatusCodeIndexSetFromClass + */ +@interface RKResponseDescriptor : NSObject + +///------------------------------------- +/// @name Creating a Response Descriptor +///------------------------------------- + +/** + Creates and returns a new `RKResponseDescriptor` object. + + This method is deprecated. Use `+ (instancetype)responseDescriptorWithMapping:(RKMapping *)mapping + method:(RKRequestMethod)method + pathPattern:(NSString *)pathPattern + keyPath:(NSString *)keyPath + statusCodes:(NSIndexSet *)statusCodes` instead. + + @param mapping The mapping for the response descriptor. + @param pathPattern A path pattern that matches against URLs for which the mapping should be used. + @param keyPath A key path specifying the subset of the parsed response for which the mapping is to be used. + @param statusCodes A set of HTTP status codes for which the mapping is to be used. + @return A new `RKResponseDescriptor` object. + */ ++ (instancetype)responseDescriptorWithMapping:(RKMapping *)mapping + pathPattern:(NSString *)pathPattern + keyPath:(NSString *)keyPath + statusCodes:(NSIndexSet *)statusCodes DEPRECATED_ATTRIBUTE; + +/** + Creates and returns a new `RKResponseDescriptor` object. + + @param mapping The mapping for the response descriptor. + @param method The HTTP method(s) for which the mapping is to be used. + @param pathPattern A path pattern that matches against URLs for which the mapping should be used. + @param keyPath A key path specifying the subset of the parsed response for which the mapping is to be used. + @param statusCodes A set of HTTP status codes for which the mapping is to be used. + @return A new `RKResponseDescriptor` object. + */ ++ (instancetype)responseDescriptorWithMapping:(RKMapping *)mapping + method:(RKRequestMethod)method + pathPattern:(NSString *)pathPattern + keyPath:(NSString *)keyPath + statusCodes:(NSIndexSet *)statusCodes; + +///------------------------------------------------------ +/// @name Getting Information About a Response Descriptor +///------------------------------------------------------ + +/** + The mapping to be used when object mapping the deserialized HTTP response body. Cannot be nil. + */ +@property (nonatomic, strong, readonly) RKMapping *mapping; + +/** + The HTTP method(s) for which the mapping is to be used. + */ +@property (nonatomic, assign, readonly) RKRequestMethod method; + +/** + The path pattern to match against the request URL. If nil, the response descriptor matches any URL. + + @see `RKPathMatcher` + */ +@property (nonatomic, copy, readonly) NSString *pathPattern; + +/** + The key path to match against the deserialized response body. If nil, the response descriptor matches the entire response body. + + When evaluating a key path match, the Foundation object parsed from the response body is sent `valueForKeyPath:` with the keyPath of the receiver. If the value returned is non-nil, object mapping is performed using the response descriptor's mapping. + */ +@property (nonatomic, copy, readonly) NSString *keyPath; + +/** + The set of status codes for which response descriptor matches. If nil, the the response descriptor matches any status code. + + @see RKStatusCodeClass + */ +@property (nonatomic, copy, readonly) NSIndexSet *statusCodes; + +///--------------------------- +/// @name Setting the Base URL +///--------------------------- + +/** + The base URL that the `pathPattern` is to be evaluated relative to. + + The base URL is set to the base URL of the object manager when a response descriptor is added to an object manager. + + @see `matchesURL:` + */ +@property (nonatomic, copy) NSURL *baseURL; + +///--------------------------------- +/// @name Using Response Descriptors +///--------------------------------- + +/** + Returns a Boolean value that indicates if the receiver's path pattern matches the given path. + + Path matching is performed using an `RKPathMatcher` object. If the receiver has a `nil` path pattern or the given path is `nil`, `YES` is returned. + + @param path The path to compare with the path pattern of the receiver. + @return `YES` if the path matches the receiver's pattern, else `NO`. + @see `RKPathMatcher` + */ +- (BOOL)matchesPath:(NSString *)path; + +/** + Returns a Boolean value that indicates if the given URL object matches the base URL and path pattern of the receiver. + + This method considers both the `baseURL` and `pathPattern` of the receiver when evaluating the given URL object. The results evaluate in the following ways: + + 1. If the `baseURL` and `pathPattern` of the receiver are both `nil`, then `YES` is returned. + 1. If the `baseURL` of the receiver is `nil`, but the path pattern is not, then the entire path and query string of the given URL will be evaluated against the path pattern of the receiver using `matchesPath:`. + 1. If the `baseURL` and the `pathPattern` are both non-nil, then the given URL is first checked to verify that it is relative to the base URL using a string prefix comparison. If the absolute string value of the given URL is prefixed with the string value of the base URL, then the URL is considered relative. If the given URL is found not to be relative to the receiver's baseURL, then `NO` is returned. If the URL is found to be relative to the base URL, then the path and query string of the URL are evaluated against the path pattern of the receiver using `matchesPath:`. + + @param URL The URL to compare with the base URL and path pattern of the receiver. + @return `YES` if the URL matches the base URL and path pattern of the receiver, else `NO`. + */ +- (BOOL)matchesURL:(NSURL *)URL; + +/** + Returns a Boolean value that indicates if the given URL response object matches the receiver. + + The match is evaluated by checking if the URL of the response matches the base URL and path pattern of the receiver via the `matchesURL:` method. If the URL is found to match, then the status code of the response is checked for inclusion in the receiver's set of status codes. + + @param response The HTTP response object to compare with the base URL, path pattern, and status codes set of the receiver. + @return `YES` if the response matches the base URL, path pattern, and status codes set of the receiver, else `NO`. + @see `matchesURL:` + */ +- (BOOL)matchesResponse:(NSHTTPURLResponse *)response; + +/** + Returns a dictionary of parsed arguments extracted from the URL of the given response object. + + @param response The HTTP response object to compare with the base URL, path pattern, and status codes set of the receiver. + @return A dictionary of parsed arguments if the response matches the base URL, path pattern, and status codes set of the receiver, else `nil`. + @see `matchesResponse:` + + */ +- (NSDictionary *)parsedArgumentsFromResponse:(NSHTTPURLResponse *)response; + +///------------------------- +/// @name Comparing Response Descriptors +///------------------------- + +/** + Returns `YES` if the receiver and the specified response descriptor are considered equivalent. + + */ +- (BOOL)isEqualToResponseDescriptor:(RKResponseDescriptor *)otherDescriptor; + +@end diff --git a/Pods/RestKit/Code/Network/RKResponseDescriptor.m b/Pods/RestKit/Code/Network/RKResponseDescriptor.m new file mode 100644 index 0000000..9c6bc0c --- /dev/null +++ b/Pods/RestKit/Code/Network/RKResponseDescriptor.m @@ -0,0 +1,211 @@ +// +// RKResponseDescriptor.m +// RestKit +// +// Created by Blake Watters on 8/16/12. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKPathMatcher.h" +#import "RKResponseDescriptor.h" +#import "RKHTTPUtilities.h" +#import "RKMapping.h" + +// Cloned from AFStringFromIndexSet -- method should be non-static for reuse +NSString *RKStringFromIndexSet(NSIndexSet *indexSet); +NSString *RKStringFromIndexSet(NSIndexSet *indexSet) +{ + NSCParameterAssert(indexSet); + NSMutableString *string = [NSMutableString string]; + + NSRange range = NSMakeRange([indexSet firstIndex], 1); + while (range.location != NSNotFound) { + NSUInteger nextIndex = [indexSet indexGreaterThanIndex:range.location]; + while (nextIndex == range.location + range.length) { + range.length++; + nextIndex = [indexSet indexGreaterThanIndex:nextIndex]; + } + + if (string.length) { + [string appendString:@","]; + } + + if (range.length == 1) { + [string appendFormat:@"%lu", (unsigned long) range.location]; + } else { + NSUInteger firstIndex = range.location; + NSUInteger lastIndex = firstIndex + range.length - 1; + [string appendFormat:@"%lu-%lu", (unsigned long) firstIndex, (unsigned long) lastIndex]; + } + + range.location = nextIndex; + range.length = 1; + } + + return string; +} + +extern NSString *RKStringDescribingRequestMethod(RKRequestMethod method); + +@interface RKResponseDescriptor () +@property (nonatomic, strong, readwrite) RKMapping *mapping; +@property (nonatomic, assign, readwrite) RKRequestMethod method; +@property (nonatomic, copy, readwrite) NSString *pathPattern; +@property (nonatomic, strong, readwrite) RKPathMatcher *pathPatternMatcher; +@property (nonatomic, copy, readwrite) NSString *keyPath; +@property (nonatomic, copy, readwrite) NSIndexSet *statusCodes; +@end + +@implementation RKResponseDescriptor + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-implementations" ++ (instancetype)responseDescriptorWithMapping:(RKMapping *)mapping + pathPattern:(NSString *)pathPattern + keyPath:(NSString *)keyPath + statusCodes:(NSIndexSet *)statusCodes +{ + return [self responseDescriptorWithMapping:mapping method:RKRequestMethodAny pathPattern:pathPattern keyPath:keyPath statusCodes:statusCodes]; +} +#pragma clang diagnostic pop + ++ (instancetype)responseDescriptorWithMapping:(RKMapping *)mapping + method:(RKRequestMethod)method + pathPattern:(NSString *)pathPattern + keyPath:(NSString *)keyPath + statusCodes:(NSIndexSet *)statusCodes +{ + NSParameterAssert(mapping); + RKResponseDescriptor *mappingDescriptor = [self new]; + mappingDescriptor.mapping = mapping; + mappingDescriptor.method = method; + mappingDescriptor.pathPattern = pathPattern; + mappingDescriptor.keyPath = keyPath; + mappingDescriptor.statusCodes = statusCodes; + + return mappingDescriptor; +} + +- (void)setPathPattern:(NSString *)pathPattern +{ + _pathPattern = pathPattern; + if (pathPattern) { + self.pathPatternMatcher = [RKPathMatcher pathMatcherWithPattern:pathPattern]; + } else { + self.pathPatternMatcher = nil; + } +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@"<%@: %p method=%@ pathPattern=%@ keyPath=%@ statusCodes=%@ : %@>", + NSStringFromClass([self class]), self, RKStringDescribingRequestMethod(self.method), self.pathPattern, self.keyPath, self.statusCodes ? RKStringFromIndexSet(self.statusCodes) : self.statusCodes, self.mapping]; +} + +- (BOOL)matchesPath:(NSString *)path +{ + return [self matchesPath:path parsedArguments:nil]; +} + +- (BOOL)matchesPath:(NSString *)path parsedArguments:(NSDictionary **)outParsedArguments +{ + if (!self.pathPattern || !path) return YES; + RKPathMatcher *pathMatcher = [RKPathMatcher pathMatcherWithPattern:self.pathPattern]; + return [pathMatcher matchesPath:path tokenizeQueryStrings:NO parsedArguments:outParsedArguments]; +} + +- (BOOL)matchesURL:(NSURL *)URL +{ + return [self matchesURL:URL parsedArguments:nil]; +} + +- (BOOL)matchesURL:(NSURL *)URL parsedArguments:(NSDictionary **)outParsedArguments +{ + NSString *pathAndQueryString = RKPathAndQueryStringFromURLRelativeToURL(URL, self.baseURL); + if (self.baseURL) { + if (! RKURLIsRelativeToURL(URL, self.baseURL)) return NO; + return [self matchesPath:pathAndQueryString parsedArguments:outParsedArguments]; + } else { + return [self matchesPath:pathAndQueryString parsedArguments:outParsedArguments]; + } +} + +- (BOOL)matchesResponse:(NSHTTPURLResponse *)response +{ + return [self matchesResponse:response parsedArguments:nil]; +} + +- (BOOL)matchesResponse:(NSHTTPURLResponse *)response parsedArguments:(NSDictionary **)outParsedArguments +{ + if (![self matchesURL:response.URL parsedArguments:outParsedArguments]) return NO; + + if (self.statusCodes) { + if (! [self.statusCodes containsIndex:response.statusCode]) { + return NO; + } + } + return YES; +} + +- (BOOL)matchesMethod:(RKRequestMethod)method +{ + return self.method & method; +} + +- (NSDictionary *)parsedArgumentsFromResponse:(NSHTTPURLResponse *)response +{ + NSDictionary *parsedArguments = nil; + if ([self matchesResponse:response parsedArguments:&parsedArguments]) + { + return parsedArguments; + } + + return nil; +} + +- (BOOL)isEqual:(id)object +{ + if (self == object) { + return YES; + } + if ([self class] != [object class]) { + return NO; + } + return [self isEqualToResponseDescriptor:object]; +} + +#define NSUINT_BIT (CHAR_BIT * sizeof(NSUInteger)) +#define NSUINTROTATE(val, howmuch) ((((NSUInteger)val) << howmuch) | (((NSUInteger)val) >> (NSUINT_BIT - howmuch))) + +- (NSUInteger)hash +{ + return NSUINTROTATE(NSUINTROTATE(NSUINTROTATE([self.mapping hash], NSUINT_BIT / 4) ^ [self.pathPattern hash], NSUINT_BIT / 4) ^ [self.keyPath hash], NSUINT_BIT / 4) ^ [self.statusCodes hash]; +} + +- (BOOL)isEqualToResponseDescriptor:(RKResponseDescriptor *)otherDescriptor +{ + if (![otherDescriptor isKindOfClass:[RKResponseDescriptor class]]) { + return NO; + } + + return + [self.mapping isEqualToMapping:otherDescriptor.mapping] && + self.method == otherDescriptor.method && + ((self.pathPattern == otherDescriptor.pathPattern) || [self.pathPattern isEqualToString:otherDescriptor.pathPattern]) && + ((self.keyPath == otherDescriptor.keyPath) || [self.keyPath isEqualToString:otherDescriptor.keyPath]) && + [self.statusCodes isEqualToIndexSet:otherDescriptor.statusCodes]; +} + +@end diff --git a/Pods/RestKit/Code/Network/RKResponseMapperOperation.h b/Pods/RestKit/Code/Network/RKResponseMapperOperation.h new file mode 100644 index 0000000..7fc04f2 --- /dev/null +++ b/Pods/RestKit/Code/Network/RKResponseMapperOperation.h @@ -0,0 +1,265 @@ +// +// RKResponseMapperOperation.h +// RestKit +// +// Created by Blake Watters on 8/16/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKMappingOperationDataSource.h" +#import "RKMapperOperation.h" +#import "RKMappingResult.h" + +#ifdef _COREDATADEFINES_H +@protocol RKManagedObjectCaching; +#endif + +/** + `RKResponseMapperOperation` is an `NSOperation` that provides support for performing object mapping on an `NSHTTPURLResponse` and its associated response data. + + This is an abstract base class encapsulating the common interface API for its concrete subclasses `RKObjectResponseMapperOperation` and `RKManagedObjectResponseMapperOperation`. + + The common behaviors encapsulated within `RKResponseMapperOperation` include: + + 1. **Handling Empty Responses**: Empty response data (see note below) requires special handling depending on the status code of the HTTP response. If an empty response is loaded with a status code in 4xx (Client Error) range, an `NSError` in the `RKErrorDomain` is created with the `NSURLErrorBadServerResponse` code to indicate that the response was not processable. If an empty response is loaded with a status code in 2xx (Successful) range, the interpretation of the response is dependent on the value of `treatsEmptyResponseAsSuccess`. When `YES`, empty responses result in the successful completion of the operation with an `RKMappingResult` containing the targetObject of the operation, if any. + 1. **Deserializing Response Data**: When started, the operation attempts to deserialize the response data into a Foundation object representation using the `RKMIMETypeSerialization` class. This deserialized representation is then made available to subclass implementations that perform the actual object mapping work. + + ## How 'Empty' Responses are Evaluated + + Any `nil` response or `NSData` object with a length equal to zero is considered empty. To support a common behavior of the widely deployed Ruby on Rails Framework, `RKResponseMapperOperation` also considers a response containing a single space character to be empty. This type of response is generated by Rails whe `render :nothing => true` is invoked. + + ## Metadata Mapping + + The `RKResponseMapperOperation` class integrates with the metadata mapping architecture. Clients of the response mapper can provide a dictionary of metadata via the `mappingMetadata` property and it will be made available to the underlying `RKMapperOperation` executed to process the response body. In addition to any user supplied metadata, the response mapper makes the following metadata key paths available for mapping: + + 1. `@metadata.HTTP.request.URL` - The `NSURL` object identifying the URL of the request that loaded the response. + 1. `@metadata.HTTP.request.method` - An `NSString` specifying the HTTP method of the request that loaded the response. + 1. `@metadata.HTTP.request.headers` - An `NSDictionary` object containing all HTTP headers and values for the request that loaded the response. + 1. `@metadata.HTTP.response.URL` - The `NSURL` object identifying the URL of the response. + 1. `@metadata.HTTP.response.headers` - An `NSDictionary` object containing all HTTP headers and values for the response. + + Please refer to the documentation accompanying `RKMappingOperation` for more details on metadata mapping. + + @see `RKMapperOperation` + */ +@interface RKResponseMapperOperation : NSOperation + +///------------------------------------------------ +/// @name Initializing a Response Mapping Operation +///------------------------------------------------ + +/** + Initializes and returns a newly created response mapper operation with the given request, HTTP response, response data, and an array of `RKResponseDescriptor` objects. + + @param request The request object for which the response was loaded. + @param response The HTTP response object to be used for object mapping. + @param data The data loaded for the response body. + @param responseDescriptors An array whose elements are `RKResponseDescriptor` objects specifying object mapping configurations that may be applied to the response. + @return The receiver, initialized with the response, data, and response descriptor objects. + */ +- (instancetype)initWithRequest:(NSURLRequest *)request + response:(NSHTTPURLResponse *)response + data:(NSData *)data + responseDescriptors:(NSArray *)responseDescriptors NS_DESIGNATED_INITIALIZER; + +///----------------------------------------------- +/// @name Accessing HTTP Request and Response Data +///----------------------------------------------- + +/** + An request object for which the response was loaded. + */ +@property (nonatomic, strong, readonly) NSURLRequest *request; + +/** + The response object that loaded the data that is to be object mapped by the operation. Cannot be `nil`. + */ +@property (nonatomic, strong, readonly) NSHTTPURLResponse *response; + +/** + The response data that is to be deserialized and mapped by the operation. May be `nil`. + */ +@property (nonatomic, strong, readonly) NSData *data; + +///--------------------------------- +/// @name Configuring Object Mapping +///--------------------------------- + +/** + An array of `RKResponseDescriptor` objects that specify object mapping configurations that may be applied to the deserialized response data if they are found to match the response. + + @see `RKResponseDescriptor` + */ +@property (nonatomic, strong, readonly) NSArray *responseDescriptors; + +/** + The target object for the object mapping operation performed on the deserialized response data. May be `nil`. + + When object mapping is being performed against a known object, the targetObject is set to ensure that the mapping is applied to the appropriate object reference. When `nil`, the mapping operation will result in the fetching or creation of new objects as necessary to satisfy the mapping configuration. + */ +@property (nonatomic, strong) id targetObject; + +/** + The delegate for the `RKMapperOperation` created by the receiver to perform object mapping on the deserialized response data. May be `nil`. + + The delegate provides access to the details of the mapping process as it is executing. Be aware that the delegate will be invoked from the thread on which the mapping is executing. + */ +@property (nonatomic, weak) id<RKMapperOperationDelegate> mapperDelegate; + +/** + An optional dictionary of metadata to make available to mapping operations executed by the receiver. + */ +@property (nonatomic, copy) NSDictionary *mappingMetadata; + +/** + A Boolean value that indicates if the receiver should consider empty responses as being successfully mapped even though no mapping is actually performed. + + When `YES` and the response data is empty (see below), a mapping result will be returned containing the target object (if any). Otherwise, the response data will be pass through to the parser which may generate an error. + + **Default:** `YES` + + @warning To support the Ruby on Rails behavior of rendering a single space character on invocation of `render :nothing => true`, a response body's containing only a single space is treated as empty. + */ +@property (nonatomic, assign) BOOL treatsEmptyResponseAsSuccess; + +/** + Returns a dictionary of key path to `RKMapping` objects that are applicable to mapping the response. This is determined by evaluating the URL and status codes of the response against the set of `responseDescriptors`. + + @see `RKResponseDescriptor` + */ +@property (nonatomic, strong, readonly) NSDictionary *responseMappingsDictionary; + +/** + Returns an array containing all `RKResponseDescriptor` objects in the configured `responseDescriptors` array that were found to match the response. + + @see `responseDescriptors` + @see `RKResponseDescriptor` + */ +@property (nonatomic, strong, readonly) NSArray *matchingResponseDescriptors; + +///-------------------------------- +/// @name Accessing Mapping Results +///-------------------------------- + +/** + The results of performing object mapping on the deserialized response data. In the event that the operation has failed, the value will is `nil`. + + The `keyPath` of each `RKResponseDescriptor` from the `responseDescriptors` set that was successfully mapped from the response data will appear as an entry in the mapping result. + */ +@property (nonatomic, strong, readonly) RKMappingResult *mappingResult; + +/** + The error, if any, that occured during execution of the operation. + */ +@property (nonatomic, strong, readonly) NSError *error; + +///---------------------------- +/// @name Configuring Callbacks +///---------------------------- + +/** + Sets a block to be executed before the response mapper operation begins mapping the deserialized response body, providing an opportunity to manipulate the mappable representation input before mapping begins. + + @param block A block object to be executed before the deserialized response is passed to the response mapper. The block has an `id` return type and must return a dictionary or array of dictionaries corresponding to the object representations that are to be mapped. The block accepts a single argument: the deserialized response data that was loaded via HTTP. If you do not wish to make any chances to the response body before mapping begins, the block should return the value passed in the `deserializedResponseBody` block argument. Returning `nil` will decline the mapping from proceeding and fail the operation with an error with the `RKMappingErrorMappingDeclined` code. + @warning The deserialized response body may or may not be immutable depending on the implementation details of the `RKSerialization` class that deserialized the response. If you wish to make changes to the mappable object representations, you must obtain a mutable copy of the response body input. + */ +- (void)setWillMapDeserializedResponseBlock:(id (^)(id deserializedResponseBody))block; + +/** + Sets a block to be executed when the response mapper operation has completed its mapping activities. This method is distinct from the `completionBlock` because it is invoked while the operation is still executing. This block is guaranteed to be called even if the receiver is cancelled before it has been started. + + @param block A block object to be executed when the response mapping is finished. The block has no return value and accepts two arguments: an `RKNappingResult` object that was mapped from the response or an `NSError` error indicating that the mapping has failed. + */ +- (void)setDidFinishMappingBlock:(void(^)(RKMappingResult *mappingResult, NSError *error))block; + +///-------------------------------------------------------- +/// @name Registering a Mapping Operation Data Source Class +///-------------------------------------------------------- + +/** + Registers the given data source class to to be used for mapper operations constructed by instances of the receiver. + + **NOTE**: The receiver class is significant to the registration: `[RKObjectResponseMapperOperation registerMappingOperationDataSourceClass:[MyDataSourceClass class]]` registers a data source for use with instances of `RKObjectResponseMapperOperation` exclusively. When registering a data source for `RKManagedObjectResponseMapperOperation` the given class must inherit from `RKManagedObjectMappingOperationDataSource`. + + @param dataSourceClass The class conforming to the RKMappingOperationDataSource protocol to be registered for use with mapper operations. + */ ++ (void)registerMappingOperationDataSourceClass:(Class<RKMappingOperationDataSource>)dataSourceClass; + +@end + +/** + `RKObjectResponseMapperOperation` is an `RKResponseMapperOperation` subclass that provides support for performing object mapping for mappings that target `NSObject` derived classes. It does not require a data source to perform its work. + */ +@interface RKObjectResponseMapperOperation : RKResponseMapperOperation +@end + +#ifdef _COREDATADEFINES_H +/** + `RKManagedObjectResponseMapperOperation` is an `RKResponseMapperOperation` subclass that provides support for performing object mapping using `RKEntityMapping` objects that target `NSManagedObject` derived classes. It requires an `NSManagedObjectContext` and a configured `RKManagedObjectMappingOperationDataSource` data source to execute successfully. + + Performing response mapping that targets Core Data managed objects imposes some additional constraints on the process that the developer should understand thoroughly: + + 1. **Permanent Managed Object IDs**: When using managed object contexts in a parent-child configuration, it is important to obtain a permanent `NSManagedObjectID` for any existing objects that are to be mapped. Mapping that occur against objecs with temporary managedObjectID's cannot be retrieved across contexts by ID. If executing an `RKManagedObjectResponseMapperOperation` against a `NSManagedObject` targetObject with a temporary ID. + 1. **Persisting Mapped Objects**: Instances of `RKManagedObjectResponseMapperOperation` do **NOT** perform any persistence on the `NSManagedObject` in which the mapping occurs. This is by design and ensures that the operation can be used to compose higher level components that handle persistence. It is the developer's responsibility to ensure that the mapped managed objects are eventually persisted. + + @see `RKManagedObjectMappingOperationDataSource` + @see `[NSManagedObjectContext obtainPermanentIDsForObjects:error:]` + */ +@interface RKManagedObjectResponseMapperOperation : RKResponseMapperOperation + +///---------------------------- +/// @name Configuring Core Data +///---------------------------- + +/** + The managed object context in which the mapping will be performed. + + @warning The `NSManagedObjectContext` given **must** have a `concurrencyType` of either `NSPrivateQueueConcurrencyType` or `NSMainQueueConcurrencyType`. Thread confined contexts are not supported. + */ +@property (nonatomic, strong) NSManagedObjectContext *managedObjectContext; + +/** + An object implementing the `RKManagedObjectCaching` protocol to be used for retrieving existing `NSManagedObject` instances by identification attributes. If `nil`, existing object cannot be retrieved and new objects will be created for all mappable content within the response data, likely resulting in the creation of duplicate objects. + + @see `RKManagedObjectCaching` + */ +@property (nonatomic, weak) id<RKManagedObjectCaching> managedObjectCache; + +/** + The permanent `NSManagedObjectID` for the target object of the mapping operation. During mapping, an instance local to the `managedObjectContext` is fetched and used to perform the mapping operation. + + If `nil` and the `targetObject` is a managed object, the `objectID` of the target object will be used. + */ +@property (nonatomic, copy) NSManagedObjectID *targetObjectID; + +@end + +#endif + +///---------------- +/// @name Functions +///---------------- + +/** + Returns a representation of a mapping result as an `NSError` value. + + The returned `NSError` object is in the `RKErrorDomain` domain and has the `RKMappingErrorFromMappingResult` code. The value for the `NSLocalizedDescriptionKey` is computed by retrieving the objects in the mapping result as an array, evaluating `valueForKeyPath:@"description"` against the array, and joining the returned error messages by comma to form a single string value. The source error objects are returned with the `NSError` in the `userInfo` dictionary under the `RKObjectMapperErrorObjectsKey` key. + + This implementation assumes that the class used to represent the response error will return a string description of the client side error when sent the `description` message. + + @return An error object representing the objects contained in the mapping result. + @see `RKErrorMessage` + */ +NSError *RKErrorFromMappingResult(RKMappingResult *mappingResult); diff --git a/Pods/RestKit/Code/Network/RKResponseMapperOperation.m b/Pods/RestKit/Code/Network/RKResponseMapperOperation.m new file mode 100644 index 0000000..81787e8 --- /dev/null +++ b/Pods/RestKit/Code/Network/RKResponseMapperOperation.m @@ -0,0 +1,533 @@ +// +// RKResponseMapperOperation.m +// RestKit +// +// Created by Blake Watters on 8/16/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKObjectMappingOperationDataSource.h" +#import "RKLog.h" +#import "RKResponseDescriptor.h" +#import "RKPathMatcher.h" +#import "RKHTTPUtilities.h" +#import "RKResponseMapperOperation.h" +#import "RKMappingErrors.h" +#import "RKMIMETypeSerialization.h" +#import "RKDictionaryUtilities.h" + +#ifdef _COREDATADEFINES_H +#if __has_include("RKCoreData.h") +#define RKCoreDataIncluded +#import "RKManagedObjectMappingOperationDataSource.h" +#endif +#endif + +// Set Logging Component +#undef RKLogComponent +#define RKLogComponent RKlcl_cRestKitNetwork + +NSError *RKErrorFromMappingResult(RKMappingResult *mappingResult) +{ + NSArray *collection = [mappingResult array]; + NSString *description = nil; + if ([collection count] > 0) { + description = [[collection valueForKeyPath:@"description"] componentsJoinedByString:@", "]; + } else { + description = @"Expected mapping result to contain at least one object to construct an error"; + RKLogWarning(@"%@", description); + } + NSDictionary *userInfo = @{RKObjectMapperErrorObjectsKey: collection, + NSLocalizedDescriptionKey: description}; + + NSError *error = [NSError errorWithDomain:RKErrorDomain code:RKMappingErrorFromMappingResult userInfo:userInfo]; + return error; +} + +static NSIndexSet *RKErrorStatusCodes() +{ + static NSIndexSet *errorStatusCodes = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + errorStatusCodes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(400, 200)]; + }); + + return errorStatusCodes; +} + +static NSError *RKUnprocessableErrorFromResponse(NSHTTPURLResponse *response) +{ + NSCAssert([RKErrorStatusCodes() containsIndex:response.statusCode], @"Expected response status code to be in the 400-599 range, instead got %ld", (long) response.statusCode); + NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; + [userInfo setValue:[NSString stringWithFormat:@"Loaded an unprocessable error response (%ld)", (long) response.statusCode] forKey:NSLocalizedDescriptionKey]; + [userInfo setValue:[response URL] forKey:NSURLErrorFailingURLErrorKey]; + + return [[NSError alloc] initWithDomain:RKErrorDomain code:NSURLErrorBadServerResponse userInfo:userInfo]; +} + +NSString *RKStringFromIndexSet(NSIndexSet *indexSet); // Defined in RKResponseDescriptor.m +static NSString *RKMatchFailureDescriptionForResponseDescriptorWithResponse(RKResponseDescriptor *responseDescriptor, NSHTTPURLResponse *response) +{ + if (responseDescriptor.statusCodes && ![responseDescriptor.statusCodes containsIndex:response.statusCode]) { + return [NSString stringWithFormat:@"response status code %ld is not within the range %@", (long) response.statusCode, RKStringFromIndexSet(responseDescriptor.statusCodes)]; + } + + NSString *pathAndQueryString = RKPathAndQueryStringFromURLRelativeToURL(response.URL, responseDescriptor.baseURL); + if (responseDescriptor.baseURL && !RKURLIsRelativeToURL(response.URL, responseDescriptor.baseURL)) { + // Not relative to the baseURL + return [NSString stringWithFormat:@"response URL '%@' is not relative to the baseURL '%@'.", response.URL, responseDescriptor.baseURL]; + } + + // Must be a path pattern mismatch + return [NSString stringWithFormat:@"response path '%@' did not match the path pattern '%@'.", pathAndQueryString, responseDescriptor.pathPattern]; +} + +static NSString *RKFailureReasonErrorStringForResponseDescriptorsMismatchWithResponse(NSArray *responseDescriptors, NSHTTPURLResponse *response) +{ + NSMutableString *failureReason = [NSMutableString string]; + [failureReason appendFormat:@"A %ld response was loaded from the URL '%@', which failed to match all (%ld) response descriptors:", + (long) response.statusCode, response.URL, (long) [responseDescriptors count]]; + + for (RKResponseDescriptor *responseDescriptor in responseDescriptors) { + [failureReason appendFormat:@"\n <RKResponseDescriptor: %p baseURL=%@ pathPattern=%@ statusCodes=%@> failed to match: %@", + responseDescriptor, responseDescriptor.baseURL, responseDescriptor.pathPattern, + responseDescriptor.statusCodes ? RKStringFromIndexSet(responseDescriptor.statusCodes) : responseDescriptor.statusCodes, + RKMatchFailureDescriptionForResponseDescriptorWithResponse(responseDescriptor, response)]; + } + + return failureReason; +} + +/** + A serial dispatch queue used for all deserialization of response bodies + */ +static dispatch_queue_t RKResponseMapperSerializationQueue() { + static dispatch_queue_t serializationQueue; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + serializationQueue = dispatch_queue_create("org.restkit.response-mapper.serialization", DISPATCH_QUEUE_SERIAL); + }); + + return serializationQueue; +} + +@interface RKResponseMapperOperation () +@property (nonatomic, strong, readwrite) NSURLRequest *request; +@property (nonatomic, strong, readwrite) NSHTTPURLResponse *response; +@property (nonatomic, strong, readwrite) NSData *data; +@property (nonatomic, strong, readwrite) NSArray *responseDescriptors; +@property (nonatomic, strong, readwrite) RKMappingResult *mappingResult; +@property (nonatomic, strong, readwrite) NSError *error; +@property (nonatomic, strong, readwrite) NSArray *matchingResponseDescriptors; +@property (nonatomic, strong, readwrite) NSDictionary *responseMappingsDictionary; +@property (nonatomic, strong, readwrite) NSDictionary *responseMappingArgumentsDictionary; +@property (nonatomic, strong) RKMapperOperation *mapperOperation; +@property (nonatomic, copy) id (^willMapDeserializedResponseBlock)(id); +@property (nonatomic, copy) void(^didFinishMappingBlock)(RKMappingResult *, NSError *); +@end + +@interface RKResponseMapperOperation (ForSubclassEyesOnly) +- (id)parseResponseData:(NSError **)error; +- (RKMappingResult *)performMappingWithObject:(id)sourceObject error:(NSError **)error; +@property (NS_NONATOMIC_IOSONLY, readonly) BOOL hasEmptyResponse; +@end + +@implementation RKResponseMapperOperation + +#pragma mark Data Source Registration + +static NSMutableDictionary *RKRegisteredResponseMapperOperationDataSourceClasses = nil; + ++ (void)initialize +{ + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + RKRegisteredResponseMapperOperationDataSourceClasses = [NSMutableDictionary new]; + }); +} + ++ (void)registerMappingOperationDataSourceClass:(Class<RKMappingOperationDataSource>)dataSourceClass +{ + if (dataSourceClass && ![(Class)dataSourceClass conformsToProtocol:@protocol(RKMappingOperationDataSource)]) { + [NSException raise:NSInvalidArgumentException format:@"Registered data source class '%@' does not conform to the `RKMappingOperationDataSource` protocol.", NSStringFromClass(dataSourceClass)]; + } + + if (dataSourceClass) { + RKRegisteredResponseMapperOperationDataSourceClasses[(id<NSCopying>)self] = dataSourceClass; + } else { + [RKRegisteredResponseMapperOperationDataSourceClasses removeObjectForKey:(id<NSCopying>)self]; + } +} + +#pragma mark + +- (instancetype)initWithRequest:(NSURLRequest *)request + response:(NSHTTPURLResponse *)response + data:(NSData *)data + responseDescriptors:(NSArray *)responseDescriptors; +{ + NSParameterAssert(request); + NSParameterAssert(response); + NSParameterAssert(responseDescriptors); + + self = [super init]; + if (self) { + self.request = request; + self.response = response; + self.data = data; + self.responseDescriptors = responseDescriptors; + self.matchingResponseDescriptors = [self buildMatchingResponseDescriptors]; + self.responseMappingsDictionary = [self buildResponseMappingsDictionary]; + self.responseMappingArgumentsDictionary = [self buildResponseMappingArgumentsDictionary]; + self.treatsEmptyResponseAsSuccess = YES; + self.mappingMetadata = @{}; // Initialize the metadata + } + + return self; +} + +- (id)parseResponseData:(NSError **)error +{ + NSString *MIMEType = [self.response MIMEType]; + __block NSError *underlyingError = nil; + __block id object; + dispatch_sync(RKResponseMapperSerializationQueue(), ^{ + object = [RKMIMETypeSerialization objectFromData:self.data MIMEType:MIMEType error:&underlyingError]; + }); + if (! object) { + NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; + [userInfo setValue:[NSString stringWithFormat:@"Loaded an unprocessable response (%ld) with content type '%@'", (long) self.response.statusCode, MIMEType] + forKey:NSLocalizedDescriptionKey]; + [userInfo setValue:[self.response URL] forKey:NSURLErrorFailingURLErrorKey]; + [userInfo setValue:underlyingError forKey:NSUnderlyingErrorKey]; + NSError *HTTPError = [[NSError alloc] initWithDomain:RKErrorDomain code:NSURLErrorCannotParseResponse userInfo:userInfo]; + + if (error) *error = HTTPError; + + return nil; + } + return object; +} + +- (NSArray *)buildMatchingResponseDescriptors +{ + NSIndexSet *indexSet = [self.responseDescriptors indexesOfObjectsPassingTest:^BOOL(RKResponseDescriptor *responseDescriptor, NSUInteger idx, BOOL *stop) { + return [responseDescriptor matchesResponse:self.response] && (RKRequestMethodFromString(self.request.HTTPMethod) & responseDescriptor.method); + }]; + return [self.responseDescriptors objectsAtIndexes:indexSet]; +} + +- (NSDictionary *)buildResponseMappingsDictionary +{ + NSMutableDictionary *dictionary = [NSMutableDictionary dictionary]; + for (RKResponseDescriptor *responseDescriptor in self.matchingResponseDescriptors) { + dictionary[(responseDescriptor.keyPath ?: [NSNull null])] = responseDescriptor.mapping; + } + + return dictionary; +} + +- (NSDictionary *)buildResponseMappingArgumentsDictionary +{ + NSMutableDictionary *dictionary = [NSMutableDictionary dictionary]; + for (RKResponseDescriptor *responseDescriptor in self.matchingResponseDescriptors) { + + NSDictionary *arguments = [responseDescriptor parsedArgumentsFromResponse:self.response]; + if (arguments) + { + // We don't add nil keypath at an [NSNull null] key, because that causes a crash later + // in RKDictionaryByMergingDictionaryWithDictionary + if (responseDescriptor.keyPath) + { + [dictionary setObject:arguments forKey:responseDescriptor.keyPath]; + } + else + { + [dictionary addEntriesFromDictionary:arguments]; + } + } + } + + return dictionary; +} + +- (RKMappingResult *)performMappingWithObject:(id)sourceObject error:(NSError **)error +{ + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:[NSString stringWithFormat:@"%@ is an abstract operation.", + NSStringFromClass([self class])] + userInfo:nil]; +} + +- (BOOL)hasEmptyResponse +{ + // NOTE: Comparison to single string whitespace character to support Ruby on Rails `render :nothing => true` + static NSData *whitespaceData = nil; + if (! whitespaceData) whitespaceData = [[NSData alloc] initWithBytes:" " length:1]; + + NSUInteger length = [self.data length]; + return (length == 0 || (length == 1 && [self.data isEqualToData:whitespaceData])); +} + +- (void)setMappingMetadata:(NSDictionary *)mappingMetadata +{ + NSDictionary *HTTPMetadata = @{ @"HTTP": @{ @"request": @{ @"URL": self.request.URL, @"method": self.request.HTTPMethod, @"headers": [self.request allHTTPHeaderFields] ?: @{} }, + @"response": @{ @"URL": self.response.URL, @"headers": [self.response allHeaderFields] ?: @{} } } }; + _mappingMetadata = RKDictionaryByMergingDictionaryWithDictionary(HTTPMetadata, mappingMetadata); + + if (self.responseMappingArgumentsDictionary) + { + NSDictionary *argumentsMetadata = @{ @"network" : @{ @"arguments" : self.responseMappingArgumentsDictionary } }; + _mappingMetadata = RKDictionaryByMergingDictionaryWithDictionary(argumentsMetadata, _mappingMetadata); + } +} + +- (void)cancel +{ + BOOL cancelledBeforeExecution = ![self isExecuting] && ![self isCancelled]; + + [super cancel]; + [self.mapperOperation cancel]; + + // NOTE: If we are cancelled before being started, then `main` and the `completionBlock` are never executed. We must ensure that we invoke `didFinishMappingBlock`, see Github issue #1494 + if (cancelledBeforeExecution) { + [self willFinish]; + } +} + +- (void)willFinish +{ + if (self.isCancelled && !self.error) self.error = [NSError errorWithDomain:RKErrorDomain code:RKOperationCancelledError userInfo:@{ NSLocalizedDescriptionKey: @"The operation was cancelled." }]; + + @synchronized(self) { + if (self.didFinishMappingBlock) { + if (self.error) self.didFinishMappingBlock(nil, self.error); + else self.didFinishMappingBlock(self.mappingResult, nil); + [self setDidFinishMappingBlock:nil]; + } + } +} + +- (void)main +{ + if (self.isCancelled) return [self willFinish]; + + BOOL isErrorStatusCode = [RKErrorStatusCodes() containsIndex:self.response.statusCode]; + + // If we are an error response and empty, we emit an error that the content is unmappable + if (isErrorStatusCode && [self hasEmptyResponse]) { + self.error = RKUnprocessableErrorFromResponse(self.response); + [self willFinish]; + return; + } + + // If we are successful and empty, we may optionally consider the response mappable (i.e. 204 response or 201 with no body) + if ([self hasEmptyResponse] && self.treatsEmptyResponseAsSuccess) { + if (self.targetObject) { + self.mappingResult = [[RKMappingResult alloc] initWithDictionary:@{[NSNull null]: self.targetObject}]; + } else { + // NOTE: For alignment with the behavior of loading an empty array or empty dictionary, if there is a nil targetObject we return a nil mappingResult. + // This informs the caller that operation succeeded, but performed no mapping. + self.mappingResult = nil; + } + + [self willFinish]; + return; + } + + // Parse the response + NSError *error; + id parsedBody = [self parseResponseData:&error]; + if (self.isCancelled) return [self willFinish]; + if (! parsedBody) { + RKLogError(@"Failed to parse response data: %@", [error localizedDescription]); + self.error = error; + [self willFinish]; + return; + } + if (self.isCancelled) return [self willFinish]; + + // Invoke the will map deserialized response block + if (self.willMapDeserializedResponseBlock) { + parsedBody = self.willMapDeserializedResponseBlock(parsedBody); + if (! parsedBody) { + NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: @"Mapping was declined due to a `willMapDeserializedResponseBlock` returning nil." }; + self.error = [NSError errorWithDomain:RKErrorDomain code:RKMappingErrorMappingDeclined userInfo:userInfo]; + RKLogError(@"Failed to parse response data: %@", [error localizedDescription]); + [self willFinish]; + return; + } + } + + // Object map the response + self.mappingResult = [self performMappingWithObject:parsedBody error:&error]; + + // If the response is a client error return either the mapping error or the mapped result to the caller as the error + if (isErrorStatusCode) { + if ([self.mappingResult count] > 0) { + error = RKErrorFromMappingResult(self.mappingResult); + } else { + // We encountered a client error that we could not map, throw unprocessable error + if (! error) error = RKUnprocessableErrorFromResponse(self.response); + } + self.error = error; + [self willFinish]; + return; + } + + // Fail if no response descriptors matched + if (error.code == RKMappingErrorNotFound && [self.responseMappingsDictionary count] == 0) { + NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: NSLocalizedString(@"No response descriptors match the response loaded.", nil), + NSLocalizedFailureReasonErrorKey: RKFailureReasonErrorStringForResponseDescriptorsMismatchWithResponse(self.responseDescriptors, self.response), + RKMappingErrorKeyPathErrorKey: [NSNull null], + NSURLErrorFailingURLErrorKey: self.response.URL, + NSURLErrorFailingURLStringErrorKey: [self.response.URL absoluteString], + NSUnderlyingErrorKey: error}; + self.error = [[NSError alloc] initWithDomain:RKErrorDomain code:RKMappingErrorNotFound userInfo:userInfo]; + [self willFinish]; + return; + } + + if (! self.mappingResult) self.error = error; + [self willFinish]; +} + +@end + +@implementation RKObjectResponseMapperOperation + +- (RKMappingResult *)performMappingWithObject:(id)sourceObject error:(NSError **)error +{ + Class dataSourceClass = RKRegisteredResponseMapperOperationDataSourceClasses[[self class]] ?: [RKObjectMappingOperationDataSource class]; + id<RKMappingOperationDataSource> dataSource = [dataSourceClass new]; + self.mapperOperation = [[RKMapperOperation alloc] initWithRepresentation:sourceObject mappingsDictionary:self.responseMappingsDictionary]; + self.mapperOperation.mappingOperationDataSource = dataSource; + self.mapperOperation.delegate = self.mapperDelegate; + self.mapperOperation.metadata = self.mappingMetadata; + if (NSLocationInRange(self.response.statusCode, RKStatusCodeRangeForClass(RKStatusCodeClassSuccessful))) { + self.mapperOperation.targetObject = self.targetObject; + } else { + RKLogInfo(@"Non-successful status code encountered: performing mapping with nil target object."); + } + [self.mapperOperation start]; + if (error) *error = self.mapperOperation.error; + return self.mapperOperation.mappingResult; +} + +@end + +#ifdef RKCoreDataIncluded + +static inline NSManagedObjectID *RKObjectIDFromObjectIfManaged(id object) +{ + return [object isKindOfClass:[NSManagedObject class]] ? [object objectID] : nil; +} + +@interface RKManagedObjectResponseMapperOperation () +@property (nonatomic, strong) NSOperationQueue *operationQueue; +@end + +@implementation RKManagedObjectResponseMapperOperation + ++ (void)registerMappingOperationDataSourceClass:(Class<RKMappingOperationDataSource>)dataSourceClass +{ + if (dataSourceClass && ![(Class)dataSourceClass isSubclassOfClass:[RKManagedObjectMappingOperationDataSource class]]) { + [NSException raise:NSInvalidArgumentException format:@"Registered data source class '%@' does not inherit from the `RKManagedObjectMappingOperationDataSource` class: You must subclass `RKManagedObjectMappingOperationDataSource` in order to register a data source class for `RKManagedObjectResponseMapperOperation`.", NSStringFromClass(dataSourceClass)]; + } + [super registerMappingOperationDataSourceClass:dataSourceClass]; +} + +- (void)cancel +{ + [super cancel]; + [self.operationQueue cancelAllOperations]; +} + +- (RKMappingResult *)performMappingWithObject:(id)sourceObject error:(NSError **)error +{ + NSAssert(self.managedObjectContext, @"Unable to perform mapping: No `managedObjectContext` assigned. (Mapping response.URL = %@)", self.response.URL); + + __block NSError *blockError = nil; + __block RKMappingResult *mappingResult = nil; + self.operationQueue = [NSOperationQueue new]; + [self.managedObjectContext performBlockAndWait:^{ + // We may have been cancelled before we made it onto the MOC's queue + if ([self isCancelled]) return; + + // Configure the mapper + self.mapperOperation = [[RKMapperOperation alloc] initWithRepresentation:sourceObject mappingsDictionary:self.responseMappingsDictionary]; + self.mapperOperation.delegate = self.mapperDelegate; + self.mapperOperation.metadata = self.mappingMetadata; + + // Configure a data source to defer execution of connection operations until mapping is complete + Class dataSourceClass = RKRegisteredResponseMapperOperationDataSourceClasses[[self class]] ?: [RKManagedObjectMappingOperationDataSource class]; + RKManagedObjectMappingOperationDataSource *dataSource = [[dataSourceClass alloc] initWithManagedObjectContext:self.managedObjectContext + cache:self.managedObjectCache]; + dataSource.operationQueue = self.operationQueue; + dataSource.parentOperation = self.mapperOperation; + + [self.operationQueue setMaxConcurrentOperationCount:1]; + [self.operationQueue setName:[NSString stringWithFormat:@"Relationship Connection Queue for '%@'", self.mapperOperation]]; + self.mapperOperation.mappingOperationDataSource = dataSource; + + if (NSLocationInRange(self.response.statusCode, RKStatusCodeRangeForClass(RKStatusCodeClassSuccessful))) { + self.mapperOperation.targetObject = self.targetObject; + + if (self.targetObjectID || self.targetObject) { + NSManagedObjectID *objectID = self.targetObjectID ?: RKObjectIDFromObjectIfManaged(self.targetObject); + if (objectID) { + if ([objectID isTemporaryID]) RKLogWarning(@"Performing object mapping to temporary target objectID. Results may not be accessible without obtaining a permanent object ID."); + NSManagedObject *localObject = [self.managedObjectContext existingObjectWithID:objectID error:&blockError]; + NSAssert(localObject == nil || localObject.managedObjectContext == nil || [localObject.managedObjectContext isEqual:self.managedObjectContext], @"Serious Core Data error: requested existing object with ID %@ in context %@, instead got an object reference in context %@. This may indicate that the objectID for your target managed object was obtained using `obtainPermanentIDsForObjects:error:` in the wrong context.", objectID, self.managedObjectContext, [localObject managedObjectContext]); + if (! localObject) { + RKLogWarning(@"Failed to retrieve existing object with ID: %@", objectID); + RKLogCoreDataError(blockError); + return; + } + self.mapperOperation.targetObject = localObject; + } else { + if (self.mapperOperation.targetObject) RKLogDebug(@"Mapping HTTP response to unmanaged target object with `RKManagedObjectResponseMapperOperation`: %@", self.mapperOperation.targetObject); + } + } else { + RKLogTrace(@"Mapping HTTP response to nil target object..."); + } + } else { + RKLogInfo(@"Non-successful status code encountered: performing mapping with nil target object."); + } + + [self.mapperOperation start]; + blockError = self.mapperOperation.error; + mappingResult = self.mapperOperation.mappingResult; + }]; + + if (self.isCancelled) return nil; + + if (! mappingResult) { + if (error) *error = blockError; + return nil; + } + + // Mapping completed without error, allow the connection operations to execute + if ([self.operationQueue operationCount]) { + RKLogTrace(@"Awaiting execution of %ld enqueued connection operations: %@", (long) [self.operationQueue operationCount], [self.operationQueue operations]); + [self.operationQueue waitUntilAllOperationsAreFinished]; + } + + return mappingResult; +} + +@end + +#endif diff --git a/Pods/RestKit/Code/Network/RKRoute.h b/Pods/RestKit/Code/Network/RKRoute.h new file mode 100644 index 0000000..66f8f91 --- /dev/null +++ b/Pods/RestKit/Code/Network/RKRoute.h @@ -0,0 +1,141 @@ +// +// RKRoute.h +// RestKit +// +// Created by Blake Watters on 5/31/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKHTTPUtilities.h" + +/** + The `RKRoute` class models a single routable path pattern in use by the application. A route can be combined with an `NSURL` base URL and interpolated with an object to produce a new fully hydrated URL object. Routes are always instantiated with a path pattern and metadata to provide for the subsequent identification of the defined route. + + There are three types of routes modeled by the RKRoute class: + + 1. **Named Routes**: A named route represents a single path and optional request method within the application. The route is not affiliated with any particular class. For example, one might define a route with the name `@"airlines_list"` as a GET to the path '/airlines.json'. + 1. **Class Routes**: An class route represents a single path that is identified by object class and request method for which it is appropriate. For example, one might define a route for the class `RKArticle` for a POST to the path '/articles.json'. + 1. **Relationship Routes**: A relationship route represents a single path through which the relationship of a parent object can be manipulated. For example, given an `RKArticle` and `RKComment` class, one might define a relationship route for the `RKArticle` class's `@"comments"` relationship as pointing to a GET to the path `@"/articles/:articleID/comments". + + The RKRoute class is internally implemented as a class cluster and is not to be directly instantiated via alloc and init. + + @see RKRouter + @see RKRouteSet + */ +@interface RKRoute : NSObject + +///--------------------------- +/// @name Instantiating Routes +///--------------------------- + +/** + Creates and returns a new named route object with the given name, path pattern and method. + + @param name A unique identifying name for the route. + @param pathPattern A SOCKit pattern describing the format of URL paths generated from the route. + @param method The request method of the route. The method given must specify a single HTTP method to be used for requests using the route. + @return A new named route object with the given name, path pattern and request method. + @raise NSInvalidArgumentException Raised if the given HTTP request method is not an exact match of the RKRequestMethod enum + */ ++ (instancetype)routeWithName:(NSString *)name pathPattern:(NSString *)pathPattern method:(RKRequestMethod)method; + +/** + Creates and returns a new class route object with the given object class, path pattern and method. + + @param objectClass The class that is represented by the route. + @param pathPattern A SOCKit pattern describing the format of URL paths generated from the route. + @param method The request method of the route. More than one method may be specified via a bitwise OR. + @return A new class route object with the given object class, path pattern and request method. + */ ++ (instancetype)routeWithClass:(Class)objectClass pathPattern:(NSString *)pathPattern method:(RKRequestMethod)method; + +/** + Creates and returns a new relationship route object with the given relationship name, object class, path pattern and method. + + @param name The name of the relationship represented by the route. + @param objectClass The class containing the relationship represented by the route. + @param pathPattern A SOCKit pattern describing the format of URL paths generated from the route. + @param method The request method of the route. More than one method may be specified via a bitwise OR. + @return A new class route object with the given object class, path pattern and request method. + */ ++ (instancetype)routeWithRelationshipName:(NSString *)name objectClass:(Class)objectClass pathPattern:(NSString *)pathPattern method:(RKRequestMethod)method; + +///--------------------------------- +/// @name Accessing Route Attributes +///--------------------------------- + +/** + The name of the receiver. + + The name is used to identify named and relationship routes and is always `nil` for object routes. + */ +@property (nonatomic, strong, readonly) NSString *name; + +/** + The object class of the receiver. + + Defines the class for which the route is appropriate. Always returns `nil` for named routes. + */ +@property (nonatomic, strong, readonly) Class objectClass; + +/** + The request method of the receiver. + + Appropriate for all route types. If the route is appropriate for any HTTP request method, then the `RKRequestMethodAny` value is used. + */ +@property (nonatomic, assign, readonly) RKRequestMethod method; + +/** + The path pattern of the receiver. + + A SOCKit pattern that describes the format of the path portion of URL's generated from the receiver. Required and used by all route types. + + @see `SOCPattern` + */ +@property (nonatomic, strong, readonly) NSString *pathPattern; + +/** + A Boolean value that determines if the path pattern should be escaped when evaluated. + + *Default*: `NO` + */ +@property (nonatomic, assign) BOOL shouldEscapePath; + +///----------------------------- +/// @name Inspecting Route Types +///----------------------------- + +/** + Determines if the receiver is a named route. + + @return YES if the receiver is a named route, else NO. + */ +@property (nonatomic, getter=isNamedRoute, readonly) BOOL namedRoute; + +/** + Determines if the receiver is a class route. + + @return YES if the receiver is a class route, else NO. + */ +@property (nonatomic, getter=isClassRoute, readonly) BOOL classRoute; + +/** + Determines if the receiver is a relationship route. + + @return YES if the receiver is a relationship route, else NO. + */ +@property (nonatomic, getter=isRelationshipRoute, readonly) BOOL relationshipRoute; + +@end diff --git a/Pods/RestKit/Code/Network/RKRoute.m b/Pods/RestKit/Code/Network/RKRoute.m new file mode 100644 index 0000000..8dbc9eb --- /dev/null +++ b/Pods/RestKit/Code/Network/RKRoute.m @@ -0,0 +1,169 @@ +// +// RKRoute.m +// RestKit +// +// Created by Blake Watters on 5/31/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKRoute.h" + +NSString *RKStringDescribingRequestMethod(RKRequestMethod method); +NSString *RKStringDescribingRequestMethod(RKRequestMethod method) +{ + if (method == RKRequestMethodAny) return @"*"; + NSMutableArray *methods = [NSMutableArray array]; + if (method & RKRequestMethodGET) [methods addObject:@"GET"]; + if (method & RKRequestMethodPOST) [methods addObject:@"POST"]; + if (method & RKRequestMethodPUT) [methods addObject:@"PUT"]; + if (method & RKRequestMethodDELETE) [methods addObject:@"DELETE"]; + if (method & RKRequestMethodHEAD) [methods addObject:@"HEAD"]; + if (method & RKRequestMethodPATCH) [methods addObject:@"PATCH"]; + if (method & RKRequestMethodOPTIONS) [methods addObject:@"OPTIONS"]; + return [NSString stringWithFormat:@"(%@)", [methods componentsJoinedByString:@"|"]]; +} + +@interface RKRoute () +@property (nonatomic, strong, readwrite) NSString *name; +@property (nonatomic, strong, readwrite) Class objectClass; +@property (nonatomic, assign, readwrite) RKRequestMethod method; +@property (nonatomic, strong, readwrite) NSString *pathPattern; +@end + +@interface RKNamedRoute : RKRoute +@end + +@interface RKClassRoute : RKRoute +@end + +@interface RKRelationshipRoute : RKRoute +@end + +@implementation RKRoute + ++ (instancetype)routeWithName:(NSString *)name pathPattern:(NSString *)pathPattern method:(RKRequestMethod)method +{ + NSParameterAssert(name); + NSParameterAssert(pathPattern); + if (!RKIsSpecificRequestMethod(method)) [NSException raise:NSInvalidArgumentException format:@"The `method` parameter must specify a single, non-ambiguous HTTP method. Bitmask values and `RKRequestMethodAny` are invalid arguments."]; + RKNamedRoute *route = [RKNamedRoute new]; + route.name = name; + route.pathPattern = pathPattern; + route.method = method; + return route; +} + ++ (instancetype)routeWithClass:(Class)objectClass pathPattern:(NSString *)pathPattern method:(RKRequestMethod)method +{ + NSParameterAssert(objectClass); + NSParameterAssert(pathPattern); + RKClassRoute *route = [RKClassRoute new]; + route.objectClass = objectClass; + route.pathPattern = pathPattern; + route.method = method; + return route; +} + ++ (instancetype)routeWithRelationshipName:(NSString *)relationshipName objectClass:(Class)objectClass pathPattern:(NSString *)pathPattern method:(RKRequestMethod)method +{ + NSParameterAssert(relationshipName); + NSParameterAssert(objectClass); + NSParameterAssert(pathPattern); + RKRelationshipRoute *route = [RKRelationshipRoute new]; + route.name = relationshipName; + route.objectClass = objectClass; + route.pathPattern = pathPattern; + route.method = method; + return route; +} + +- (instancetype)init +{ + self = [super init]; + if (self) { + if ([self isMemberOfClass:[RKRoute class]]) { + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:[NSString stringWithFormat:@"%@ is not meant to be directly instantiated. Use one of the initializer methods instead.", + NSStringFromClass([self class])] + userInfo:nil]; + } + } + + return self; +} + +- (BOOL)isNamedRoute +{ + return NO; +} + +- (BOOL)isClassRoute +{ + return NO; +} + +- (BOOL)isRelationshipRoute +{ + return NO; +} + +@end + +@implementation RKNamedRoute + +- (BOOL)isNamedRoute +{ + return YES; +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@"<%@: %p name=%@ method=%@ pathPattern=%@>", + NSStringFromClass([self class]), self, self.name, RKStringDescribingRequestMethod(self.method), self.pathPattern]; +} + +@end + +@implementation RKClassRoute + +- (BOOL)isClassRoute +{ + return YES; +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@"<%@: %p objectClass=%@ method=%@ pathPattern=%@>", + NSStringFromClass([self class]), self, NSStringFromClass(self.objectClass), + RKStringDescribingRequestMethod(self.method), self.pathPattern]; +} + +@end + +@implementation RKRelationshipRoute + +- (BOOL)isRelationshipRoute +{ + return YES; +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@"<%@: %p relationshipName=%@ objectClass=%@ method=%@ pathPattern=%@>", + NSStringFromClass([self class]), self, self.name, NSStringFromClass(self.objectClass), + RKStringDescribingRequestMethod(self.method), self.pathPattern]; +} + +@end diff --git a/Pods/RestKit/Code/Network/RKRouteSet.h b/Pods/RestKit/Code/Network/RKRouteSet.h new file mode 100644 index 0000000..6cb3502 --- /dev/null +++ b/Pods/RestKit/Code/Network/RKRouteSet.h @@ -0,0 +1,159 @@ +// +// RKRouteSet.h +// RestKit +// +// Created by Blake Watters on 5/31/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKRoute.h" + +/** + The `RKRouteSet` class provides for the storage and retrieval of `RKRoute` objects. Route objects are added and removed the route set to manipulate the routing table of the application. + + @see `RKRouter` + */ +@interface RKRouteSet : NSObject + +///--------------------------------- +/// @name Adding and Removing Routes +///--------------------------------- + +/** + Adds a route to the receiver. + + @param route The route to be added. + @raises NSInvalidArgumentException Raised if the route already exists in the receiver or overlaps an existing name. + */ +- (void)addRoute:(RKRoute *)route; + +/** + Adds all routes from the given array to the receiver. All objects within the given array must be an instance of `RKRoute` or else an `NSInvalidArgumentException` will be raised. + + @param routes An array of `RKRoute` objects to be added to the receiver. + */ +- (void)addRoutes:(NSArray *)routes; + +/** + Removes a route from the receiver. + + @param route The route to be removed. + @raises NSInvalidArgumentException Raised if the route does not exist in the receiver. + */ +- (void)removeRoute:(RKRoute *)route; + +///--------------------------- +/// @name Querying a Route Set +///--------------------------- + +/** + Determines if a given route exists within the receiver. + + @param route The route to be tested for containement. + @return `YES` if the route is contained within the route set, else `NO`. + */ +- (BOOL)containsRoute:(RKRoute *)route; + +/** + Returns all routes from the receiver in an array. + + @return An array containing all the routes in the receiver. + */ +@property (nonatomic, readonly, copy) NSArray *allRoutes; + +/** + Returns all named routes from the receiver in an array. + + @return An array containing all the named routes in the receiver. + */ +@property (nonatomic, readonly, copy) NSArray *namedRoutes; + +/** + Returns all class routes from the receiver in an array. + + @return An array containing all the class routes in the receiver. + */ +@property (nonatomic, readonly, copy) NSArray *classRoutes; + +/** + Returns all relationship routes from the receiver in an array. + + @return An array containing all the relationship routes in the receiver. + */ +@property (nonatomic, readonly, copy) NSArray *relationshipRoutes; + +/** + Retrieves a route with the given name. + + @param name The name of the named route to be found. + @return A route with the given name or nil if none was found. + */ +- (RKRoute *)routeForName:(NSString *)name; + +/** + Retrieves a route for the given object class and request method. + + @param objectClass The object class of the route to be retrieved. + @param method The request method of the route to be retrieved. + @return A route with the given object class and method or nil if none was found. + */ +- (RKRoute *)routeForClass:(Class)objectClass method:(RKRequestMethod)method; + +/** + Retrieves a route for a given relationship of a class with a given request method. + + @param relationship The name of the relationship of the route to be retrieved. + @param method The request method of the route to be retrieved. + @return A route with the given relationship name, object class and method or nil if none was found. + */ +- (RKRoute *)routeForRelationship:(NSString *)relationship ofClass:(Class)objectClass method:(RKRequestMethod)method; + +/** + Retrieves all class routes with a given object class. + + Class matches are determined by direct comparison of the class objects. The inheritance hierarchy is not consulted. + + @param objectClass The object class of the routes to be retrieved. + @return An array containing all class routes with the given class. + */ +- (NSArray *)routesForClass:(Class)objectClass; + +/** + Retrieves all object routes for a given object. + + All object routes are searched and returned if they target a class or superclass of the given object (using `- [NSObject isKindOfClass:]`). + + @param object An object for which all object routes are to be retrieved. + @return An array containing all object routes where the target class is included in the given object's class hierarchy. + */ +- (NSArray *)routesForObject:(id)object; + +/** + Retrieves all routes for a given relationship name and object class. + + @param relationshipName The name of the relationship of the routes to be retrieved. + @param objectClass The object class of the routes to be retrieved. + @return An array containing all relationship routes with the given relationship name and object class. + */ +- (NSArray *)routesForRelationship:(NSString *)relationshipName ofClass:(Class)objectClass; + +/** + Retrieves a route for a given object and request method. + + The object routes are first searched for an exact match with the given object's class and request method. If no exact match is found for the given request method, but a route is found for the `RKRequestMethodAny` method, it is returned. If neither are found, the search process begins again and traverses up the inheritance hierarchy. + */ +- (RKRoute *)routeForObject:(id)object method:(RKRequestMethod)method; + +@end diff --git a/Pods/RestKit/Code/Network/RKRouteSet.m b/Pods/RestKit/Code/Network/RKRouteSet.m new file mode 100644 index 0000000..1038b61 --- /dev/null +++ b/Pods/RestKit/Code/Network/RKRouteSet.m @@ -0,0 +1,212 @@ +// +// RKRouteSet.m +// RestKit +// +// Created by Blake Watters on 5/31/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKRouteSet.h" +#import "RKPathMatcher.h" + +@interface RKRouteSet () + +@property (nonatomic, strong) NSMutableArray *routes; + +@end + +@implementation RKRouteSet + + +- (instancetype)init +{ + self = [super init]; + if (self) { + self.routes = [NSMutableArray array]; + } + + return self; +} + + +- (NSArray *)allRoutes +{ + return [NSArray arrayWithArray:self.routes]; +} + +- (NSArray *)namedRoutes +{ + NSMutableArray *routes = [NSMutableArray array]; + for (RKRoute *route in self.routes) { + if ([route isNamedRoute]) [routes addObject:route]; + } + + return [NSArray arrayWithArray:routes]; +} + +- (NSArray *)classRoutes +{ + NSMutableArray *routes = [NSMutableArray array]; + for (RKRoute *route in self.routes) { + if ([route isClassRoute]) [routes addObject:route]; + } + + return [NSArray arrayWithArray:routes]; +} + +- (NSArray *)relationshipRoutes +{ + NSMutableArray *routes = [NSMutableArray array]; + for (RKRoute *route in self.routes) { + if ([route isRelationshipRoute]) [routes addObject:route]; + } + + return [NSArray arrayWithArray:routes]; +} + +- (void)addRoute:(RKRoute *)route +{ + NSAssert(![self containsRoute:route], @"Cannot add a route that is already added to the router."); + NSAssert(![route isNamedRoute] || [self routeForName:route.name] == nil, @"Cannot add a route with the same name as an existing route."); + if ([route isClassRoute]) { + RKRoute *existingRoute = [self routeForClass:route.objectClass method:route.method]; + if (! (existingRoute == nil || (existingRoute.method == RKRequestMethodAny && route.method != RKRequestMethodAny) || (route.method == RKRequestMethodAny && existingRoute.method != RKRequestMethodAny))) [NSException raise:NSInternalInconsistencyException format:@"Cannot add a route with the same class and method as an existing route."]; + } else if ([route isRelationshipRoute]) { + NSArray *routes = [self routesForRelationship:route.name ofClass:route.objectClass]; + for (RKRoute *existingRoute in routes) { + NSAssert(existingRoute.method != route.method, @"Cannot add a relationship route with the same name and class as an existing route."); + (void)existingRoute; + } + } + [self.routes addObject:route]; +} + +- (void)addRoutes:(NSArray *)routes +{ + for (RKRoute *route in routes) { + if (! [route isKindOfClass:[RKRoute class]]) [NSException raise:NSInvalidArgumentException format:@"Unexpected object of type `%@` encountered in array of routes.", [route class]]; + [self addRoute:route]; + } +} + +- (void)removeRoute:(RKRoute *)route +{ + NSAssert([self containsRoute:route], @"Cannot remove a route that is not added to the router."); + [self.routes removeObject:route]; +} + +- (BOOL)containsRoute:(RKRoute *)route +{ + return [self.routes containsObject:route]; +} + +- (RKRoute *)routeForName:(NSString *)name +{ + for (RKRoute *route in [self namedRoutes]) { + if ([route.name isEqualToString:name]) { + return route; + } + } + + return nil; +} + +- (RKRoute *)routeForClass:(Class)objectClass method:(RKRequestMethod)method +{ + // Check for an exact match + for (RKRoute *route in [self classRoutes]) { + if ([route.objectClass isEqual:objectClass] && (route.method != RKRequestMethodAny && route.method & method)) { + return route; + } + } + + // Check for wildcard match + for (RKRoute *route in [self classRoutes]) { + if ([route.objectClass isEqual:objectClass] && route.method == RKRequestMethodAny) { + return route; + } + } + + return nil; +} + +- (RKRoute *)routeForRelationship:(NSString *)relationshipName ofClass:(Class)objectClass method:(RKRequestMethod)method +{ + for (RKRoute *route in [self relationshipRoutes]) { + if ([route.name isEqualToString:relationshipName] && [route.objectClass isEqual:objectClass] && (route.method == method || route.method == RKRequestMethodAny)) { + return route; + } + } + + return nil; +} + +- (NSArray *)routesForClass:(Class)objectClass +{ + NSMutableArray *routes = [NSMutableArray array]; + for (RKRoute *route in [self classRoutes]) { + if ([route.objectClass isEqual:objectClass]) { + [routes addObject:route]; + } + } + + return [NSArray arrayWithArray:routes]; +} + +- (NSArray *)routesForObject:(id)object +{ + NSMutableArray *routes = [NSMutableArray array]; + for (RKRoute *route in [self classRoutes]) { + if ([object isKindOfClass:route.objectClass]) { + [routes addObject:route]; + } + } + + return [NSArray arrayWithArray:routes]; +} + +- (NSArray *)routesForRelationship:(NSString *)relationshipName ofClass:(Class)objectClass +{ + NSIndexSet *indexes = [self.relationshipRoutes indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) { + return [[(RKRoute *)obj objectClass] isEqual:objectClass] && [[(RKRoute *)obj name] isEqualToString:relationshipName]; + }]; + + return [self.relationshipRoutes objectsAtIndexes:indexes]; +} + +- (RKRoute *)routeForObject:(id)object method:(RKRequestMethod)method +{ + Class searchClass = [object class]; + while (searchClass) { + NSArray *routes = [self routesForClass:searchClass]; + RKRoute *wildcardRoute = nil; + RKRoute *bitMaskMatch = nil; + for (RKRoute *route in routes) { + if (route.method == method) return route; + + // We want to favor bitmask matches separate from the Any wildcard match + if (route.method == RKRequestMethodAny) wildcardRoute = route; + else if (route.method & method) bitMaskMatch = route; + } + + if (bitMaskMatch) return bitMaskMatch; + if (wildcardRoute) return wildcardRoute; + searchClass = [searchClass superclass]; + } + + return nil; +} + +@end diff --git a/Pods/RestKit/Code/Network/RKRouter.h b/Pods/RestKit/Code/Network/RKRouter.h new file mode 100644 index 0000000..f8f7221 --- /dev/null +++ b/Pods/RestKit/Code/Network/RKRouter.h @@ -0,0 +1,118 @@ +// +// RKRouter.h +// RestKit +// +// Created by Blake Watters on 6/20/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKHTTPUtilities.h" + +@class RKRouteSet; +@class RKRoute; + +/** + An `RKRouter` instance is responsible for generating `NSURL` objects with a given base URL and a route set. It is used to centralize the knowledge about the URL's that are used by the application. + + ## Route Generation + + URL's can be generated by the router in three ways: + + 1. **By name**. Named routes link a symbolic name with a path and an HTTP request method. (see `URLForRouteNamed:method:object:`) + 2. **By object**. Routes can be defined by class and HTTP request method. When a URL is requested from the router for an object, the router will identify the most appropriate route for the object and instantiate an `NSURL` with the route's path pattern and interpolate it against the object. (see `URLForObject:method:`) + 3. **By object relationship**. Routes can be defined for relationships to other objects. When a URL is requested from the router for a relationship, the router will retrieve the appropriate route for the relationship from the route set and interpolate the route's path pattern against the source object. (see `URLForRelationship:ofObject:method:`) + + @see `RKRoute` + @see `RKRouteSet` + */ +@interface RKRouter : NSObject + +- (instancetype)init __attribute__((unavailable("Invoke initWithBaseURL: instead."))); + +///---------------------------- +/// @name Initializing a Router +///---------------------------- + +/** + Initializes a router with a given base URL. + + @param baseURL The base URL with which to initialize the receiver. + @return The receiver, initialized with the given base URL. + */ +- (instancetype)initWithBaseURL:(NSURL *)baseURL NS_DESIGNATED_INITIALIZER; + +///---------------------- +/// @name Generating URLs +///---------------------- + +/** + Generates a URL for the route with the given name. + + The route set is searched for a route with the given name and a new `NSURL` object is instantiated with the baseURL of the receiver and the path pattern of the route, optionally interpolated with a given object. If a pointer to an `RKRequestMethod` variable is provided, the HTTP method for the route will be assigned to the reference. + + @param routeName The name of the route for which a URL is to be generated. + @param method A pointer to an `RKRequestMethod` variable in which to store the HTTP method associated with the named route. May be nil. + @param object An optional object against which to interpolate the path pattern. + @return A new `NSURL` object constructed by appending the path pattern to the baseURL of the receiver and interpolating against a given object; or nil if no route was found with the given name. + */ +- (NSURL *)URLForRouteNamed:(NSString *)routeName method:(out RKRequestMethod *)method object:(id)object; + +/** + Generates a URL for a given object and HTTP method. + + The route set is searched for a route that matches the HTTP method and class of the object being routed. If there is not an exact match for the object's class, the inheritance hierarchy is searched until a match is found or all possible routes are exhausted. Exact HTTP request matches are favored over the wildcard method (`RKRequestMethodAny`). Once the appropriate route is identified, a new `NSURL` object is instantiated with the baseURL of the receiver and the path pattern of the route, interpolated against the object being routed. + + @param object The object for which a URL is to be generated. + @param method The HTTP method for which the URL is to be generated. + @return A new URL object constructed by appending the path pattern of the route for the object an HTTP method to the baseURL of the receiver, interpolated against the routed object; or nil if no route was found for the given object and HTTP method. + */ +- (NSURL *)URLForObject:(id)object method:(RKRequestMethod)method; + +/** + Generates a URL for a relationship of a given object with a given HTTP method. + + The route set is searched for a route that matches the relationship of the given object's class and the given HTTP method. If a matching route is found, a new `NSURL` object is instantiated with the baseURL of the receiver and the path pattern of the route, interpolated against the object being routed. + + @param relationshipName The name of the relationship for which a URL is to be generated. + @param object The object for which the URL is to be generated. + @param method The HTTP method for which the URL is to be generated. + @return A new URL object constructed by appending the path pattern of the route for the given object's relationship and HTTP method to the baseURL of the receiver, interpolated against the routed object; or nil if no route was found for the given relationship, object and HTTP method. + */ +- (NSURL *)URLForRelationship:(NSString *)relationshipName ofObject:(id)object method:(RKRequestMethod)method; + +/** + Generates a URL with a given route and object. + + @param route The route to generate the URL with. + @param object The object with which to interpolate the path pattern of the given route. + @return A new URL object constructed by interpolating the path pattern of the given route with the given object to construct a path and constructing an `NSURL` object relative to the `baseURL` of the receiver. + */ +- (NSURL *)URLWithRoute:(RKRoute *)route object:(id)object; + +///--------------------------------------------- +/// @name Configuring the Base URL and Route Set +///--------------------------------------------- + +/** + The base URL that all URLs constructed by the receiver are relative to. + */ +@property (nonatomic, strong, readwrite) NSURL *baseURL; + +/** + A route set defining all the routes addressable through the receiver. + */ +@property (nonatomic, strong, readonly) RKRouteSet *routeSet; + +@end diff --git a/Pods/RestKit/Code/Network/RKRouter.m b/Pods/RestKit/Code/Network/RKRouter.m new file mode 100644 index 0000000..2d5565f --- /dev/null +++ b/Pods/RestKit/Code/Network/RKRouter.m @@ -0,0 +1,85 @@ +// +// RKRouter.m +// RestKit +// +// Created by Blake Watters on 6/20/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKRouter.h" +#import "RKRouteSet.h" +#import "RKRoute.h" +#import "RKPathMatcher.h" +#import <objc/runtime.h> + +@interface RKRouter () +@property (nonatomic, strong, readwrite) RKRouteSet *routeSet; +@end + +@implementation RKRouter + +- (instancetype)initWithBaseURL:(NSURL *)baseURL +{ + self = [super init]; + if (self) { + NSParameterAssert(baseURL); + self.baseURL = baseURL; + self.routeSet = [[RKRouteSet alloc] init]; + } + + return self; +} + +- (instancetype)init +{ + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:[NSString stringWithFormat:@"%@ Failed to call designated initializer. Invoke initWithBaseURL: instead.", NSStringFromClass([self class])] + userInfo:nil]; +} + +- (NSURL *)URLForRouteNamed:(NSString *)routeName method:(out RKRequestMethod *)method object:(id)object +{ + RKRoute *route = [self.routeSet routeForName:routeName]; + if (method) *method = route.method; + return [self URLWithRoute:route object:object]; +} + +- (NSURL *)URLForObject:(id)object method:(RKRequestMethod)method +{ + RKRoute *route = [self.routeSet routeForObject:object method:method]; + return [self URLWithRoute:route object:object]; +} + +- (NSURL *)URLForRelationship:(NSString *)relationshipName ofObject:(id)object method:(RKRequestMethod)method +{ + RKRoute *route = [self.routeSet routeForRelationship:relationshipName ofClass:[object class] method:method]; + return [self URLWithRoute:route object:object]; +} + +- (NSURL *)URLWithRoute:(RKRoute *)route object:(id)object +{ + NSParameterAssert(route); + NSURL *URL = [NSURL URLWithString:[self pathFromRoute:route forObject:object] relativeToURL:self.baseURL]; + return URL; +} + +- (NSString *)pathFromRoute:(RKRoute *)route forObject:(id)object +{ + if (! object) return route.pathPattern; + RKPathMatcher *pathMatcher = [RKPathMatcher pathMatcherWithPattern:route.pathPattern]; + return [pathMatcher pathFromObject:object addingEscapes:route.shouldEscapePath interpolatedParameters:nil]; +} + +@end diff --git a/Pods/RestKit/Code/ObjectMapping.h b/Pods/RestKit/Code/ObjectMapping.h new file mode 100644 index 0000000..1ad0b8c --- /dev/null +++ b/Pods/RestKit/Code/ObjectMapping.h @@ -0,0 +1,29 @@ +// +// ObjectMapping.h +// RestKit +// +// Created by Blake Watters on 9/30/10. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import <RKValueTransformers/RKValueTransformers.h> + +#import "RKObjectMapping.h" +#import "RKAttributeMapping.h" +#import "RKRelationshipMapping.h" +#import "RKMappingResult.h" +#import "RKMapperOperation.h" +#import "RKDynamicMapping.h" +#import "RKErrorMessage.h" diff --git a/Pods/RestKit/Code/ObjectMapping/RKAttributeMapping.h b/Pods/RestKit/Code/ObjectMapping/RKAttributeMapping.h new file mode 100644 index 0000000..6d08f96 --- /dev/null +++ b/Pods/RestKit/Code/ObjectMapping/RKAttributeMapping.h @@ -0,0 +1,60 @@ +// +// RKAttributeMapping.h +// RestKit +// +// Created by Blake Watters on 4/30/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKPropertyMapping.h" + +/** + Instances of `RKAttributeMapping` define a transformation of data between an attribute value on source object and an attribute value on a destination object within an object mapping. + */ +@interface RKAttributeMapping : RKPropertyMapping + +/** + Creates and returns a new attribute mapping specifying that data is to be read from a given key path on a source object + and set to a given key path on a destination object. + + Attribute mappings define transformation between key paths in the source and destination object beings mapped. In the simplest + case, an attribute mapping may simply specify that data from one object is to be copied to another. A common example of this + type of transformation is copying the `name` key from a JSON payload onto a local object. In this case, the source and + destination key paths are identical, as are the source and destination types (`NSString`), so a simple get and set operation + has been defined. + + The next most common use-case is the transformation of identical data between two different key paths in the + source and destination objects. This is typically encountered when you wish to transform inbound data to conform with the naming + conventions of the platform or the data model of your application. An example of this type of transformation would be from the + source key path of `first_name` to the destination key path of `firstName`. In this transformation, the key paths have diverged + but both sides of the mapping correspond to NSString properties. + + The final type of transformation to be specified via an attribute mapping involves the transformation between types in the mapping. + By far, the most common example of this use-case is the transformation of a inbound string or numeric property into a date on + the target object. For example, consider a backend system that returns the creation date of a piece of content in a JSON payload. + This data might be returned in JSON as `{"created_on": "2012-08-27"}`. In a given application, the developer may wish to model this + data as an NSDate `createdOn` property on the target object. An attribute mapping to support this mapping would specify a source + key path of `created_on` and a destination key path of `createdOn`. On the destination object, the `createdOn` property would be defined + as `@property (nonatomic, strong) NSDate *createdOn;`. At mapping time, the mapping operation inspects the type of the content being + mapped and attempts to transform the source content into the type of the desination property specified by the mapping. In this case, + an NSDateFormatter object would be used to process the inbound `NSString` into an outbound `NSDate` object. + + @param sourceKeyPath The key path on the source object from which to read the data being mapped. If `nil`, then the entire source object representation is mapped to the specified destination attribute. + @param destinationKeyPath The key path on the destination object on which to set the mapped data. + @return A newly created attribute mapping object that is ready to be added to an object mapping. + */ ++ (instancetype)attributeMappingFromKeyPath:(NSString *)sourceKeyPath toKeyPath:(NSString *)destinationKeyPath; + +@end diff --git a/Pods/RestKit/Code/ObjectMapping/RKAttributeMapping.m b/Pods/RestKit/Code/ObjectMapping/RKAttributeMapping.m new file mode 100644 index 0000000..6d83f06 --- /dev/null +++ b/Pods/RestKit/Code/ObjectMapping/RKAttributeMapping.m @@ -0,0 +1,39 @@ +// +// RKAttributeMapping.m +// RestKit +// +// Created by Blake Watters on 4/30/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKAttributeMapping.h" + +@interface RKPropertyMapping () +@property (nonatomic, copy, readwrite) NSString *sourceKeyPath; +@property (nonatomic, copy, readwrite) NSString *destinationKeyPath; +@end + +@implementation RKAttributeMapping + ++ (instancetype)attributeMappingFromKeyPath:(NSString *)sourceKeyPath toKeyPath:(NSString *)destinationKeyPath +{ + NSAssert(sourceKeyPath || destinationKeyPath, @"Both the source and destination key paths cannot be nil"); + RKAttributeMapping *attributeMapping = [self new]; + attributeMapping.sourceKeyPath = sourceKeyPath; + attributeMapping.destinationKeyPath = destinationKeyPath; + return attributeMapping; +} + +@end diff --git a/Pods/RestKit/Code/ObjectMapping/RKDynamicMapping.h b/Pods/RestKit/Code/ObjectMapping/RKDynamicMapping.h new file mode 100644 index 0000000..ba60aca --- /dev/null +++ b/Pods/RestKit/Code/ObjectMapping/RKDynamicMapping.h @@ -0,0 +1,115 @@ +// +// RKDynamicMapping.h +// RestKit +// +// Created by Blake Watters on 7/28/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKMapping.h" +#import "RKObjectMappingMatcher.h" + +/** + The `RKDynamicMapping` class is an `RKMapping` subclass that provides an interface for deferring the decision about how a given object representation is to be mapped until run time. This enables many interesting mapping strategies, such as mapping similarly structured data differently and constructing object mappings at run time by examining the data being mapped. + + ## Configuring Mapping Selection + + Dynamic mappings support the selection of the concrete object mapping in one of two ways: + + 1. Through the use of a mapping selection block configured by `setObjectMappingForRepresentationBlock:`. When configured, the block is called with a reference to the current object representation being mapped and is expected to return an `RKObjectMapping` object. Returning `nil` declines the mapping of the representation. + 1. Through the configuration of one of more `RKObjectMappingMatcher` objects. The matchers are consulted in registration order and the first matcher to return an object mapping is used to map the matched representation. + + When both a mapping selection block and matchers are configured on a `RKDynamicMapping` object, the matcher objects are consulted first and if none match, the selection block is invoked. + + ## Using Matcher Objects + + The `RKObjectMappingMatcher` class provides an interface for evaluating a key path or predicate based match and returning an appropriate object mapping. Matchers can be added to the `RKDynamicMapping` objects to declaratively describe a particular mapping strategy. + + For example, suppose that we have a JSON fragment for a person that we want to map differently based on the gender of the person. When the gender is 'male', we want to use the Boy class and when then the gender is 'female' we want to use the Girl class. The JSON might look something like this: + + [ { "name": "Blake", "gender": "male" }, { "name": "Sarah", "gender": "female" } ] + + We might define configure the dynamic mapping like so: + + RKDynamicMapping *mapping = [RKDynamicMapping new]; + RKObjectMapping *boyMapping = [RKObjectMapping mappingForClass:[Boy class]]; + RKObjectMapping *girlMapping = [RKObjectMapping mappingForClass:[Girl class]]; + [mapping addMatcher:[RKObjectMappingMatcher matcherWithKeyPath:@"gender" expectedValue:@"male" objectMapping:boyMapping]]; + [mapping addMatcher:[RKObjectMappingMatcher matcherWithKeyPath:@"gender" expectedValue:@"female" objectMapping:girlMapping]]; + + When evaluated, the matchers will invoke `valueForKeyPath:@"gender"` against each dictionary in the array of object representations and apply the appropriate object mapping for each representation. This would return a mapping result containing an array of two objects, one an instance of the `Boy` class and the other an instance of the `Girl` class. + + ## HTTP Integration + + Dynamic mappings can be used to map HTTP requests and responses by adding them to an `RKRequestDescriptor` or `RKResponseDescriptor` objects. + */ +@interface RKDynamicMapping : RKMapping + +///------------------------------------------ +/// @name Configuring Block Mapping Selection +///------------------------------------------ + +/** + Sets a block to be invoked to determine the appropriate concrete object mapping with which to map an object representation. + + @param block The block object to invoke to select the object mapping with which to map the given object representation. The block returns an object mapping and accepts a single parameter: the object representation being mapped. + */ +- (void)setObjectMappingForRepresentationBlock:(RKObjectMapping *(^)(id representation))block; + +/** + Returns the array of matchers objects added to the receiver. + */ +@property (nonatomic, strong, readonly) NSArray *matchers; + +/** + Adds a matcher to the receiver. + + If the matcher has already been added to the receiver, then adding it again moves it to the top of the matcher stack. + + @param matcher The matcher to add to the receiver. + */ +- (void)addMatcher:(RKObjectMappingMatcher *)matcher; + +/** + Removes a matcher from the receiver. + + If the matcher has already been added to the receiver, then adding it again moves it to the top of the matcher stack. + + @param matcher The matcher to remove from the receiver. + */ +- (void)removeMatcher:(RKObjectMappingMatcher *)matcher; + +/** + Returns an array of object mappings that have been registered with the receiver. + + @return An array of `RKObjectMapping` objects registered with the receiver. + */ +@property (nonatomic, readonly) NSArray *objectMappings; + +///----------------------------------------------------------------- +/// @name Retrieving the Object Mapping for an Object Representation +///----------------------------------------------------------------- + +/** + Invoked by the `RKMapperOperation` and `RKMappingOperation` to determine the appropriate `RKObjectMapping` to use when mapping the given object representation. + + This method searches the stack of registered matchers and then executes the block, if any, set by `setObjectMappingForRepresentationBlock:`. If `nil` is returned, then mapping for the representation is declined and it will not be mapped. + + @param representation The object representation that being mapped dynamically for which to determine the appropriate concrete mapping. + @return The object mapping to be used to map the given object representation. + */ +- (RKObjectMapping *)objectMappingForRepresentation:(id)representation; + +@end diff --git a/Pods/RestKit/Code/ObjectMapping/RKDynamicMapping.m b/Pods/RestKit/Code/ObjectMapping/RKDynamicMapping.m new file mode 100644 index 0000000..f7138ba --- /dev/null +++ b/Pods/RestKit/Code/ObjectMapping/RKDynamicMapping.m @@ -0,0 +1,119 @@ +// +// RKDynamicMapping.m +// RestKit +// +// Created by Blake Watters on 7/28/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKDynamicMapping.h" +#import "RKObjectMappingMatcher.h" +#import "RKLog.h" + +// Set Logging Component +#undef RKLogComponent +#define RKLogComponent RKlcl_cRestKitObjectMapping + +@interface RKDynamicMapping () +@property (nonatomic, strong) NSMutableArray *mutableMatchers; +@property (nonatomic, strong) NSArray *possibleObjectMappings; +@property (nonatomic, copy) RKObjectMapping *(^objectMappingForRepresentationBlock)(id representation); +@end + +@implementation RKDynamicMapping + +- (instancetype)init +{ + self = [super init]; + if (self) { + self.mutableMatchers = [NSMutableArray new]; + self.possibleObjectMappings = [NSArray new]; + } + + return self; +} + +- (NSArray *)matchers +{ + return [self.mutableMatchers copy]; +} + +- (NSArray *)objectMappings +{ + return self.possibleObjectMappings; +} + +- (void)addMatcher:(RKObjectMappingMatcher *)matcher +{ + NSParameterAssert(matcher); + if ([self.mutableMatchers containsObject:matcher]) { + [self.mutableMatchers removeObject:matcher]; + [self.mutableMatchers insertObject:matcher atIndex:0]; + } else { + [self.mutableMatchers addObject:matcher]; + + NSArray *newPossibleMappings = [matcher possibleObjectMappings]; + if (newPossibleMappings.count > 0) { + self.possibleObjectMappings = [self.possibleObjectMappings arrayByAddingObjectsFromArray:newPossibleMappings]; + } + } +} + +- (void)removeMatcher:(RKObjectMappingMatcher *)matcher +{ + NSParameterAssert(matcher); + + if ([self.mutableMatchers containsObject:matcher]) { + NSMutableArray *mappings = [self.possibleObjectMappings mutableCopy]; + for (RKObjectMapping *mapping in [matcher possibleObjectMappings]) { + /* removeObject will remove *all* instances; if we have dups we just want to remove one */ + NSUInteger idx = [mappings indexOfObject:mapping]; + if (idx != NSNotFound) + [mappings removeObjectAtIndex:idx]; + } + self.possibleObjectMappings = [mappings copy]; + [self.mutableMatchers removeObject:matcher]; + } +} + +- (RKObjectMapping *)objectMappingForRepresentation:(id)representation +{ + RKObjectMapping *mapping = nil; + + RKLogTrace(@"Performing dynamic object mapping for object representation: %@", representation); + + // Consult the declarative matchers first + for (RKObjectMappingMatcher *matcher in self.mutableMatchers) { + if ([matcher matches:representation]) { + RKLogTrace(@"Found declarative match for matcher: %@.", matcher); + return matcher.objectMapping; + } + } + + // Otherwise consult the block + if (self.objectMappingForRepresentationBlock) { + mapping = self.objectMappingForRepresentationBlock(representation); + if (mapping) RKLogTrace(@"Determined concrete `RKObjectMapping` using object mapping for representation block"); + } + + return mapping; +} + +- (BOOL)isEqualToMapping:(RKMapping *)otherMapping +{ + return (self == otherMapping); +} + +@end diff --git a/Pods/RestKit/Code/ObjectMapping/RKErrorMessage.h b/Pods/RestKit/Code/ObjectMapping/RKErrorMessage.h new file mode 100644 index 0000000..2aea33f --- /dev/null +++ b/Pods/RestKit/Code/ObjectMapping/RKErrorMessage.h @@ -0,0 +1,44 @@ +// +// RKError.h +// RestKit +// +// Created by Jeremy Ellison on 5/10/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import <Foundation/Foundation.h> + +/** + The `RKErrorMessage` is a simple class used for representing error messages returned by a remote backend system with which the client application is communicating. Error messages are typically returned in a response body in the Client Error class (status code 4xx range). + + @see `RKErrorFromMappingResult` + */ +@interface RKErrorMessage : NSObject + +///----------------------------------- +/// @name Accessing Errror Information +///----------------------------------- + +/** + The error message to be presented to the user. + */ +@property (nonatomic, copy) NSString *errorMessage; + +/** + A dictionary of application specific information that accompanies the error message. + */ +@property (nonatomic, copy) NSDictionary *userInfo; + +@end diff --git a/Pods/RestKit/Code/ObjectMapping/RKErrorMessage.m b/Pods/RestKit/Code/ObjectMapping/RKErrorMessage.m new file mode 100644 index 0000000..1a102c4 --- /dev/null +++ b/Pods/RestKit/Code/ObjectMapping/RKErrorMessage.m @@ -0,0 +1,30 @@ +// +// RKError.m +// RestKit +// +// Created by Jeremy Ellison on 5/10/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKErrorMessage.h" + +@implementation RKErrorMessage + +- (NSString *)description +{ + return self.errorMessage; +} + +@end diff --git a/Pods/RestKit/Code/ObjectMapping/RKHTTPUtilities.h b/Pods/RestKit/Code/ObjectMapping/RKHTTPUtilities.h new file mode 100644 index 0000000..b1f0553 --- /dev/null +++ b/Pods/RestKit/Code/ObjectMapping/RKHTTPUtilities.h @@ -0,0 +1,159 @@ +// +// RKHTTPUtilities.h +// RestKit +// +// Created by Blake Watters on 8/24/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import <Foundation/Foundation.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** + HTTP methods for requests + */ +typedef NS_OPTIONS(NSInteger, RKRequestMethod) { + RKRequestMethodGET = 1 << 0, + RKRequestMethodPOST = 1 << 1, + RKRequestMethodPUT = 1 << 2, + RKRequestMethodDELETE = 1 << 3, + RKRequestMethodHEAD = 1 << 4, + RKRequestMethodPATCH = 1 << 5, + RKRequestMethodOPTIONS = 1 << 6, + RKRequestMethodAny = (RKRequestMethodGET | + RKRequestMethodPOST | + RKRequestMethodPUT | + RKRequestMethodDELETE | + RKRequestMethodHEAD | + RKRequestMethodPATCH | + RKRequestMethodOPTIONS) +}; + +/** + Returns YES if the given HTTP request method is an exact match of the RKRequestMethod enum, and NO if it's a bit mask combination. + */ +BOOL RKIsSpecificRequestMethod(RKRequestMethod method); + +/** + Returns the corresponding string for value for a given HTTP request method. + + For example, given `RKRequestMethodGET` would return `@"GET"`. + + @param method The request method to return the corresponding string value for. The given request method must be specific. + */ +NSString *RKStringFromRequestMethod(RKRequestMethod method); + +/** + Returns the corresponding request method value for a given string. + + For example, given `@"PUT"` would return `@"RKRequestMethodPUT"` + */ +RKRequestMethod RKRequestMethodFromString(NSString *); + +/** + The HTTP status code classes + + See http://tools.ietf.org/html/rfc2616#section-10 + */ +typedef NS_ENUM(NSUInteger, RKStatusCodeClass) { + RKStatusCodeClassInformational = 100, + RKStatusCodeClassSuccessful = 200, + RKStatusCodeClassRedirection = 300, + RKStatusCodeClassClientError = 400, + RKStatusCodeClassServerError = 500 +}; + +/** + Creates a new range covering the status codes in the given class. + + @param statusCodeClass The status code class to create a range covering. + @return A new range covering the status codes in the given class. + */ +NSRange RKStatusCodeRangeForClass(RKStatusCodeClass statusCodeClass); + +/** + Creates a new index set covering the status codes in the given class. + + @param statusCodeClass The status code class to create an index set covering. + @return A new index set covering the status codes in the given class. + */ +NSIndexSet *RKStatusCodeIndexSetForClass(RKStatusCodeClass statusCodeClass); + +/** + Creates and returns a new index set including all HTTP response status codes that are cacheable. + + @return A new index set containing all cacheable status codes. + */ +NSIndexSet *RKCacheableStatusCodes(void); + +/** + Returns string representation of a given HTTP status code. + + The list of supported status codes was built from http://en.wikipedia.org/wiki/List_of_HTTP_status_codes + + @param statusCode The HTTP status code to return a string from. + @return A string representation of the given status code. + */ +NSString *RKStringFromStatusCode(NSInteger statusCode); + +/** + Parse HTTP Date: http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3.1 + */ +NSDate *RKDateFromHTTPDateString(NSString *); + +/** + Returns the cache expiration data from a dictionary of HTTP response headers as appropriate for the given status code. If the status code is not cachable, `nil` is returned. + + @param headers The HTTP response headers from which to extract the cache expiration date. + @param statusCode The HTTP response status code of the response. + @return The expiration date as specified by the cache headers or `nil` if none was found. + */ +NSDate *RKHTTPCacheExpirationDateFromHeadersWithStatusCode(NSDictionary *headers, NSInteger statusCode); + +/** + Returns a Boolean value that indicates if a given URL is relative to another URL. + + This method does not rely on the `baseURL` method of `NSURL` as it only indicates a relationship between the initialization of two URL objects. The relativity of the given URL is assessed by evaluating a prefix match of the URL's absolute string value with the absolute string value of the potential base URL. + + @param URL The URL to assess the relativity of. + @param baseURL The base URL to determine if the given URL is relative to. + @return `YES` is URL is relative to the base URL, else `NO`. + */ +BOOL RKURLIsRelativeToURL(NSURL *URL, NSURL *baseURL); + +/** + Returns a string object containing the relative path and query string of a given URL object and a base URL that the given URL is relative to. + + If the given URL is found not to be relative to the baseURL, `nil` is returned. + + @param URL The URL to retrieve the relative path and query string of. + @param baseURL The base URL to be omitted from the returned path and query string. + @return A string containing the relative path and query parameters. + */ +NSString *RKPathAndQueryStringFromURLRelativeToURL(NSURL *URL, NSURL *baseURL); + +/** + * Returns an index set of the status codes with optional response bodies + * + * @return An index set of the status codes with optional response bodies + */ +NSIndexSet *RKStatusCodesOfResponsesWithOptionalBodies(void); + +#ifdef __cplusplus +} +#endif diff --git a/Pods/RestKit/Code/ObjectMapping/RKHTTPUtilities.m b/Pods/RestKit/Code/ObjectMapping/RKHTTPUtilities.m new file mode 100644 index 0000000..1b4aafe --- /dev/null +++ b/Pods/RestKit/Code/ObjectMapping/RKHTTPUtilities.m @@ -0,0 +1,571 @@ +// +// RKHTTPUtilities.m +// RestKit +// +// Created by Blake Watters on 8/24/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKHTTPUtilities.h" + +NSUInteger RKStatusCodeRangeLength = 100; + +NSRange RKStatusCodeRangeForClass(RKStatusCodeClass statusCodeClass) +{ + return NSMakeRange(statusCodeClass, RKStatusCodeRangeLength); +} + +NSIndexSet *RKStatusCodeIndexSetForClass(RKStatusCodeClass statusCodeClass) +{ + return [NSIndexSet indexSetWithIndexesInRange:RKStatusCodeRangeForClass(statusCodeClass)]; +} + +NSIndexSet *RKCacheableStatusCodes(void) +{ + NSMutableIndexSet *cacheableStatusCodes = [NSMutableIndexSet indexSet]; + [cacheableStatusCodes addIndex:200]; + [cacheableStatusCodes addIndex:304]; + [cacheableStatusCodes addIndex:203]; + [cacheableStatusCodes addIndex:300]; + [cacheableStatusCodes addIndex:301]; + [cacheableStatusCodes addIndex:302]; + [cacheableStatusCodes addIndex:307]; + [cacheableStatusCodes addIndex:410]; + return cacheableStatusCodes; +} + +BOOL RKIsSpecificRequestMethod(RKRequestMethod method) +{ + // check for a power of two + return !(method & (method - 1)); +} + +NSString *RKStringFromRequestMethod(RKRequestMethod method) +{ + switch (method) { + case RKRequestMethodGET: return @"GET"; + case RKRequestMethodPOST: return @"POST"; + case RKRequestMethodPUT: return @"PUT"; + case RKRequestMethodPATCH: return @"PATCH"; + case RKRequestMethodDELETE: return @"DELETE"; + case RKRequestMethodHEAD: return @"HEAD"; + case RKRequestMethodOPTIONS: return @"OPTIONS"; + default: break; + } + return nil; +} + +RKRequestMethod RKRequestMethodFromString(NSString *methodName) +{ + if ([methodName isEqualToString:@"GET"]) return RKRequestMethodGET; + else if ([methodName isEqualToString:@"POST"]) return RKRequestMethodPOST; + else if ([methodName isEqualToString:@"PUT"]) return RKRequestMethodPUT; + else if ([methodName isEqualToString:@"DELETE"]) return RKRequestMethodDELETE; + else if ([methodName isEqualToString:@"HEAD"]) return RKRequestMethodHEAD; + else if ([methodName isEqualToString:@"PATCH"]) return RKRequestMethodPATCH; + else if ([methodName isEqualToString:@"OPTIONS"]) return RKRequestMethodOPTIONS; + else @throw [NSException exceptionWithName:NSInvalidArgumentException + reason:[NSString stringWithFormat:@"The given HTTP request method name `%@` does not correspond to any known request methods.", methodName] + userInfo:nil]; +} + +// Built from http://en.wikipedia.org/wiki/List_of_HTTP_status_codes +static NSDictionary *RKStatusCodesToNamesDictionary() +{ + static NSDictionary *statusCodesToNamesDictionary = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + statusCodesToNamesDictionary = @{ + // 1xx (Informational) + @(100): @"Continue", + @(101): @"Switching Protocols", + @(102): @"Processing", + + // 2xx (Success) + @(200): @"OK", + @(201): @"Created", + @(202): @"Accepted", + @(203): @"Non-Authoritative Information", + @(204): @"No Content", + @(205): @"Reset Content", + @(206): @"Partial Content", + @(207): @"Multi-Status", + @(208): @"Already Reported", + @(226): @"IM Used", + + // 3xx (Redirection) + @(300): @"Multiple Choices", + @(301): @"Moved Permanently", + @(302): @"Found", + @(303): @"See Other", + @(304): @"Not Modified", + @(305): @"Use Proxy", + @(306): @"Switch Proxy", + @(307): @"Temporary Redirect", + @(308): @"Permanent Redirect", + + // 4xx (Client Error) + @(400): @"Bad Request", + @(401): @"Unauthorized", + @(402): @"Payment Required", + @(403): @"Forbidden", + @(404): @"Not Found", + @(405): @"Method Not Allowed", + @(406): @"Not Acceptable", + @(407): @"Proxy Authentication Required", + @(408): @"Request Timeout", + @(409): @"Conflict", + @(410): @"Gone", + @(411): @"Length Required", + @(412): @"Precondition Failed", + @(413): @"Request Entity Too Large", + @(414): @"Request-URI Too Long", + @(415): @"Unsupported Media Type", + @(416): @"Requested Range Not Satisfiable", + @(417): @"Expectation Failed", + @(418): @"I'm a teapot", + @(420): @"Enhance Your Calm", + @(422): @"Unprocessable Entity", + @(423): @"Locked", + @(424): @"Failed Dependency", + @(424): @"Method Failure", + @(425): @"Unordered Collection", + @(426): @"Upgrade Required", + @(428): @"Precondition Required", + @(429): @"Too Many Requests", + @(431): @"Request Header Fields Too Large", + @(451): @"Unavailable For Legal Reasons", + + // 5xx (Server Error) + @(500): @"Internal Server Error", + @(501): @"Not Implemented", + @(502): @"Bad Gateway", + @(503): @"Service Unavailable", + @(504): @"Gateway Timeout", + @(505): @"HTTP Version Not Supported", + @(506): @"Variant Also Negotiates", + @(507): @"Insufficient Storage", + @(508): @"Loop Detected", + @(509): @"Bandwidth Limit Exceeded", + @(510): @"Not Extended", + @(511): @"Network Authentication Required", + }; + }); + return statusCodesToNamesDictionary; +} + +NSString * RKStringFromStatusCode(NSInteger statusCode) +{ + return RKStatusCodesToNamesDictionary()[@(statusCode)]; +} + + +/** + Below is ragel source used to compile those tables. The output was polished / pretty-printed and tweaked from ragel. + As the generated code is "hard" to debug, we store the code in http-date.r1 + + shell% ragel -F1 http-date.rl + shell% gcc -o http-date http-date.c + shell% ./http-date 'Sun, 06 Nov 1994 08:49:37 GMT' 'Sunday, 06-Nov-94 08:49:37 GMT' 'Sun Nov 6 08:49:37 1994' 'Sat Dec 24 14:34:26 2037' 'Sunday, 06-Nov-94 08:49:37 GMT' 'Sun, 06 Nov 1994 08:49:37 GMT' + */ +static const char _httpDate_trans_keys[] = { + 0, 0, 70, 87, 114, 114, 105, 105, 32, 100, 65, 83, 112, 117, 114, 114, 32, + 32, 32, 57, 48, 57, 32, 32, 48, 57, 48, 57, 58, 58, 48, 57, 48, 57, + 58, 58, 48, 57, 48, 57, 32, 32, 48, 57, 48, 57, 48, 57, 48, 57, 103, + 103, 101, 101, 99, 99, 101, 101, 98, 98, 97, 117, 110, 110, 108, 110, 97, 97, + 114, 121, 111, 111, 118, 118, 99, 99, 116, 116, 101, 101, 112, 112, 32, 32, 48, + 57, 48, 57, 32, 32, 65, 83, 112, 117, 114, 114, 32, 32, 48, 57, 48, 57, + 48, 57, 48, 57, 32, 32, 48, 57, 48, 57, 58, 58, 48, 57, 48, 57, 58, + 58, 48, 57, 48, 57, 32, 32, 71, 71, 77, 77, 84, 84, 103, 103, 101, 101, + 99, 99, 101, 101, 98, 98, 97, 117, 110, 110, 108, 110, 97, 97, 114, 121, 111, + 111, 118, 118, 99, 99, 116, 116, 101, 101, 112, 112, 97, 97, 121, 121, 44, 44, + 32, 32, 48, 57, 48, 57, 45, 45, 65, 83, 112, 117, 114, 114, 45, 45, 48, + 57, 48, 57, 32, 32, 48, 57, 48, 57, 58, 58, 48, 57, 48, 57, 58, 58, + 48, 57, 48, 57, 32, 32, 71, 71, 77, 77, 84, 84, 103, 103, 101, 101, 99, + 99, 101, 101, 98, 98, 97, 117, 110, 110, 108, 110, 97, 97, 114, 121, 111, 111, + 118, 118, 99, 99, 116, 116, 101, 101, 112, 112, 111, 111, 110, 110, 97, 117, 116, + 116, 32, 117, 114, 114, 100, 100, 104, 117, 117, 117, 32, 114, 115, 115, 101, 101, + 32, 115, 101, 101, 100, 100, 32, 110, 101, 101, 0, 0, 0, 0, 0, 0, 0 +}; + +static const char _httpDate_key_spans[] = { + 0, 18, 1, 1, 69, 19, 6, 1, 1, 26, 10, 1, 10, 10, 1, 10, 10, + 1, 10, 10, 1, 10, 10, 10, 10, 1, 1, 1, 1, 1, 21, 1, 3, 1, + 8, 1, 1, 1, 1, 1, 1, 1, 10, 10, 1, 19, 6, 1, 1, 10, 10, + 10, 10, 1, 10, 10, 1, 10, 10, 1, 10, 10, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 21, 1, 3, 1, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 10, 10, 1, 19, 6, 1, 1, 10, 10, 1, 10, 10, 1, 10, 10, 1, + 10, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 21, 1, 3, 1, 8, 1, + 1, 1, 1, 1, 1, 1, 1, 21, 1, 86, 1, 1, 14, 1, 83, 1, 1, + 84, 1, 1, 79, 1, 0, 0, 0 +}; + +static const short _httpDate_index_offsets[] = { + 0, 0, 19, 21, 23, 93, 113, 120, 122, 124, 151, 162, 164, 175, 186, 188, 199, + 210, 212, 223, 234, 236, 247, 258, 269, 280, 282, 284, 286, 288, 290, 312, 314, 318, + 320, 329, 331, 333, 335, 337, 339, 341, 343, 354, 365, 367, 387, 394, 396, 398, 409, + 420, 431, 442, 444, 455, 466, 468, 479, 490, 492, 503, 514, 516, 518, 520, 522, 524, + 526, 528, 530, 532, 554, 556, 560, 562, 571, 573, 575, 577, 579, 581, 583, 585, 587, + 589, 591, 602, 613, 615, 635, 642, 644, 646, 657, 668, 670, 681, 692, 694, 705, 716, + 718, 729, 740, 742, 744, 746, 748, 750, 752, 754, 756, 758, 780, 782, 786, 788, 797, + 799, 801, 803, 805, 807, 809, 811, 813, 835, 837, 924, 926, 928, 943, 945, 1029, 1031, + 1033, 1118, 1120, 1122, 1202, 1204, 1205, 1206 +}; + +static const unsigned char _httpDate_indicies[] = { + 0, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 3, 4, 1, 1, + 5, 1, 6, 1, 7, 1, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 10, 1, 11, 1, 1, 12, 1, 13, 1, 1, 1, + 14, 1, 1, 15, 16, 17, 1, 1, 1, 18, 1, 19, 1, 1, 1, 1, 20, + 1, 21, 1, 22, 1, 23, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 1, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 1, 26, 1, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 1, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 1, 29, + 1, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 1, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 1, 32, 1, 33, 33, 33, 33, 33, 33, 33, 33, 33, + 33, 1, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 1, 35, 1, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 1, 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 1, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 1, 39, 39, 39, + 39, 39, 39, 39, 39, 39, 39, 1, 40, 1, 41, 1, 42, 1, 43, 1, 44, + 1, 45, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 46, 1, 47, 1, 48, 1, 49, 1, 50, 1, 51, 1, 1, + 1, 1, 1, 1, 52, 1, 53, 1, 54, 1, 55, 1, 56, 1, 57, 1, 58, + 1, 59, 1, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 1, 61, 61, 61, + 61, 61, 61, 61, 61, 61, 61, 1, 62, 1, 63, 1, 1, 64, 1, 65, 1, + 1, 1, 66, 1, 1, 67, 68, 69, 1, 1, 1, 70, 1, 71, 1, 1, 1, + 1, 72, 1, 73, 1, 74, 1, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, + 1, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 1, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 1, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 1, + 79, 1, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 1, 81, 81, 81, 81, + 81, 81, 81, 81, 81, 81, 1, 82, 1, 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 1, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 1, 85, 1, 86, + 86, 86, 86, 86, 86, 86, 86, 86, 86, 1, 87, 87, 87, 87, 87, 87, 87, + 87, 87, 87, 1, 88, 1, 89, 1, 90, 1, 91, 1, 92, 1, 93, 1, 94, + 1, 95, 1, 96, 1, 97, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 98, 1, 99, 1, 100, 1, 101, 1, 102, + 1, 103, 1, 1, 1, 1, 1, 1, 104, 1, 105, 1, 106, 1, 107, 1, 108, + 1, 109, 1, 110, 1, 111, 1, 112, 1, 113, 1, 114, 1, 115, 115, 115, 115, + 115, 115, 115, 115, 115, 115, 1, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, + 1, 117, 1, 118, 1, 1, 119, 1, 120, 1, 1, 1, 121, 1, 1, 122, 123, + 124, 1, 1, 1, 125, 1, 126, 1, 1, 1, 1, 127, 1, 128, 1, 129, 1, + 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 1, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 1, 132, 1, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, + 1, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 1, 135, 1, 136, 136, 136, + 136, 136, 136, 136, 136, 136, 136, 1, 137, 137, 137, 137, 137, 137, 137, 137, 137, + 137, 1, 138, 1, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 1, 140, 140, + 140, 140, 140, 140, 140, 140, 140, 140, 1, 141, 1, 142, 1, 143, 1, 144, 1, + 145, 1, 146, 1, 147, 1, 148, 1, 149, 1, 150, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 151, 1, 152, 1, + 153, 1, 154, 1, 155, 1, 156, 1, 1, 1, 1, 1, 1, 157, 1, 158, 1, + 159, 1, 160, 1, 161, 1, 162, 1, 163, 1, 164, 1, 7, 1, 165, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 164, 1, 166, 1, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 167, 1, 168, 1, 10, 1, 169, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 170, 1, 171, 1, 8, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 172, 1, 168, 1, 173, 1, 8, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 9, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 168, 1, 174, 1, 175, 1, + 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 176, 1, 172, 1, 1, 1, 1, + 0 +}; + +static const unsigned char _httpDate_trans_targs[] = { + 2, 0, 124, 126, 131, 137, 3, 4, 5, 41, 82, 6, 26, 28, 30, 33, 35, + 37, 39, 7, 25, 8, 9, 10, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 141, 8, 27, 8, 29, 8, 31, 32, 8, 8, 8, 34, + 8, 8, 36, 8, 38, 8, 40, 8, 42, 43, 44, 45, 46, 67, 69, 71, 74, + 76, 78, 80, 47, 66, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63, 64, 65, 142, 48, 68, 48, 70, 48, 72, 73, 48, 48, 48, + 75, 48, 48, 77, 48, 79, 48, 81, 48, 83, 84, 85, 86, 87, 88, 89, 90, + 109, 111, 113, 116, 118, 120, 122, 91, 108, 92, 93, 94, 95, 96, 97, 98, 99, + 100, 101, 102, 103, 104, 105, 106, 107, 143, 92, 110, 92, 112, 92, 114, 115, 92, + 92, 92, 117, 92, 92, 119, 92, 121, 92, 123, 92, 125, 127, 128, 129, 130, 132, + 135, 133, 134, 136, 138, 139, 140 +}; + +static const char _httpDate_trans_actions[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 0, 2, 2, 0, 3, 3, 0, 4, 4, 0, 5, + 5, 0, 6, 6, 6, 6, 7, 0, 8, 0, 9, 0, 0, 10, 11, 12, 0, + 13, 14, 0, 15, 0, 16, 0, 17, 0, 2, 2, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 0, 6, 6, 6, 6, 0, 3, 3, 0, 4, 4, + 0, 5, 5, 0, 0, 0, 0, 7, 0, 8, 0, 9, 0, 0, 10, 11, 12, + 0, 13, 14, 0, 15, 0, 16, 0, 17, 0, 0, 0, 0, 2, 2, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 6, 18, 0, 3, 3, 0, + 4, 4, 0, 5, 5, 0, 0, 0, 0, 7, 0, 8, 0, 9, 0, 0, 10, + 11, 12, 0, 13, 14, 0, 15, 0, 16, 0, 17, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0 +}; + +static const char _httpDate_eof_actions[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 19, 20, 21 +}; + +static NSDate *_parseHTTPDate(const char *buf, size_t bufLen) { + const char *p = buf, *pe = p + bufLen, *eof = pe; + int parsed = 0, cs = 1; + NSDate *date = NULL; + +#if (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && (__IPHONE_OS_VERSION_MAX_ALLOWED < 70000)) || \ +(defined(MAC_OS_X_VERSION_MAX_ALLOWED) && (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_9)) + CFGregorianDate gdate; + memset(&gdate, 0, sizeof(CFGregorianDate)); +#else + NSDateComponents *gdate = [[NSDateComponents alloc] init]; +#endif + + { + int _slen, _trans; + const char *_keys; + const unsigned char *_inds; + if(p == pe) { goto _test_eof; } + _resume: + _keys = _httpDate_trans_keys + (cs << 1); + _inds = _httpDate_indicies + _httpDate_index_offsets[cs]; + _slen = _httpDate_key_spans[cs]; + _trans = _inds[(_slen > 0) && (_keys[0] <= (*p)) && ((*p) <= _keys[1]) ? (*p) - _keys[0] : _slen]; + cs = _httpDate_trans_targs[_trans]; + + if(_httpDate_trans_actions[_trans] == 0) { goto _again; } + + switch(_httpDate_trans_actions[_trans]) { + case 6: gdate.year = gdate.year * 10 + ((*p) - '0'); break; + case 18: gdate.year = gdate.year * 10 + ((*p) - '0'); gdate.year += 1900; break; + case 10: gdate.month = 1; break; + case 9: gdate.month = 2; break; + case 13: gdate.month = 3; break; + case 1: gdate.month = 4; break; + case 14: gdate.month = 5; break; + case 12: gdate.month = 6; break; + case 11: gdate.month = 7; break; + case 7: gdate.month = 8; break; + case 17: gdate.month = 9; break; + case 16: gdate.month = 10; break; + case 15: gdate.month = 11; break; + case 8: gdate.month = 12; break; + case 2: gdate.day = gdate.day * 10 + ((*p) - '0'); break; + case 3: gdate.hour = gdate.hour * 10 + ((*p) - '0'); break; + case 4: gdate.minute = gdate.minute * 10 + ((*p) - '0'); break; + case 5: gdate.second = gdate.second * 10.0 + ((*p) - '0'); break; + } + + _again: + if( cs == 0) { goto _out; } + if(++p != pe) { goto _resume; } + _test_eof: {} + if(p == eof) { + switch(_httpDate_eof_actions[cs]) { + case 19: parsed = 1; break; + case 20: parsed = 1; break; + case 21: parsed = 1; break; + } + } + + _out: {} + } + + static dispatch_once_t onceToken; + +#if (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && (__IPHONE_OS_VERSION_MAX_ALLOWED < 70000)) || \ +(defined(MAC_OS_X_VERSION_MAX_ALLOWED) && (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_9)) + static CFTimeZoneRef gmtTimeZone; + dispatch_once(&onceToken, ^{ + gmtTimeZone = CFTimeZoneCreateWithTimeIntervalFromGMT(NULL, 0.0); + }); + + if (parsed == 1) { + date = [NSDate dateWithTimeIntervalSinceReferenceDate:CFGregorianDateGetAbsoluteTime(gdate, gmtTimeZone)]; + } +#else + static NSCalendar *gregorian; + dispatch_once(&onceToken, ^{ + gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian]; + gregorian.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:0]; + }); + + if (parsed == 1) { + date = [gregorian dateFromComponents:gdate]; + } +#endif + + return(date); +} + +/* + * Parse HTTP Date: http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3.1 + */ +NSDate * RKDateFromHTTPDateString(NSString *httpDate) +{ + char stringBuffer[256]; + size_t stringLength = (size_t)CFStringGetLength((__bridge CFStringRef)httpDate); + const char *cStringPtr = (const char *)CFStringGetCStringPtr((__bridge CFStringRef)httpDate, kCFStringEncodingMacRoman); + if(cStringPtr == NULL) { + CFIndex usedBytes = 0L, convertedCount = 0L; + convertedCount = CFStringGetBytes((__bridge CFStringRef)httpDate, CFRangeMake(0L, (CFIndex)stringLength), kCFStringEncodingUTF8, '?', NO, (UInt8 *)stringBuffer, sizeof(stringBuffer) - 1L, &usedBytes); + if(((size_t)convertedCount != stringLength) || (usedBytes < 0L)) { return(NULL); } + stringBuffer[usedBytes] = '\0'; + cStringPtr = (const char *)stringBuffer; + } + return(_parseHTTPDate(cStringPtr, stringLength)); +} + +static float const kRKURLCacheLastModFraction = 0.1f; // 10% since Last-Modified suggested by RFC2616 section 13.2.4 +static float const kRKURLCacheDefault = 3600.0f; // Default cache expiration delay if none defined (1 hour) + +/* + * This method tries to determine the expiration date based on a response headers dictionary. + */ +NSDate * RKHTTPCacheExpirationDateFromHeadersWithStatusCode(NSDictionary *headers, NSInteger statusCode) +{ + if (statusCode != 200 && statusCode != 203 && statusCode != 300 && statusCode != 301 && statusCode != 302 && statusCode != 307 && statusCode != 410) { + // Uncacheable response status code + return nil; + } + + // Check Pragma: no-cache + NSString *pragma = headers[@"Pragma"]; + if (pragma && [pragma isEqualToString:@"no-cache"]) { + // Uncacheable response + return nil; + } + + // Define "now" based on the request + NSString *date = headers[@"Date"]; + // If no Date: header, define now from local clock + NSDate *now = date ? RKDateFromHTTPDateString(date) : [NSDate date]; + + // Look at info from the Cache-Control: max-age=n header + NSString *cacheControl = [headers[@"Cache-Control"] lowercaseString]; + if (cacheControl) + { + NSRange foundRange = [cacheControl rangeOfString:@"no-store"]; + if (foundRange.length > 0) { + // If no-store, the content cannot be cached at all + // See http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.2 + return nil; + } + + foundRange = [cacheControl rangeOfString:@"no-cache"]; + if (foundRange.length > 0) { + // If no-cache, we must revalidate with the origin server + // See http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.1 + return nil; + } + + NSInteger maxAge; + foundRange = [cacheControl rangeOfString:@"max-age"]; + if (foundRange.length > 0) { + NSScanner *cacheControlScanner = [NSScanner scannerWithString:cacheControl]; + [cacheControlScanner setScanLocation:foundRange.location + foundRange.length]; + [cacheControlScanner scanString:@"=" intoString:nil]; + if ([cacheControlScanner scanInteger:&maxAge]) { + return maxAge > 0 ? [[NSDate alloc] initWithTimeInterval:maxAge sinceDate:now] : nil; + } + } + } + + // If not Cache-Control found, look at the Expires header + NSString *expires = headers[@"Expires"]; + if (expires) { + NSTimeInterval expirationInterval = 0; + NSDate *expirationDate = RKDateFromHTTPDateString(expires); + if (expirationDate) { + expirationInterval = [expirationDate timeIntervalSinceDate:now]; + } + if (expirationInterval > 0) { + // Convert remote expiration date to local expiration date + return [NSDate dateWithTimeIntervalSinceNow:expirationInterval]; + } + else { + // If the Expires header can't be parsed or is expired, do not cache + return nil; + } + } + + if (statusCode == 302 || statusCode == 307) { + // If not explict cache control defined, do not cache those status + return nil; + } + + // If no cache control defined, try some heristic to determine an expiration date + NSString *lastModified = headers[@"Last-Modified"]; + if (lastModified) { + NSTimeInterval age = 0; + NSDate *lastModifiedDate = RKDateFromHTTPDateString(lastModified); + if (lastModifiedDate) { + // Define the age of the document by comparing the Date header with the Last-Modified header + age = [now timeIntervalSinceDate:lastModifiedDate]; + } + return age > 0 ? [NSDate dateWithTimeIntervalSinceNow:(age * kRKURLCacheLastModFraction)] : nil; + } + + // If nothing permitted to define the cache expiration delay nor to restrict its cacheability, use a default cache expiration delay + return [[NSDate alloc] initWithTimeInterval:kRKURLCacheDefault sinceDate:now]; +} + +BOOL RKURLIsRelativeToURL(NSURL *URL, NSURL *baseURL) +{ + return [[URL absoluteString] hasPrefix:[baseURL absoluteString]]; +} + +NSString *RKPathAndQueryStringFromURLRelativeToURL(NSURL *URL, NSURL *baseURL) +{ + if (baseURL) { + if (! RKURLIsRelativeToURL(URL, baseURL)) return nil; + return [[URL absoluteString] substringFromIndex:[[baseURL absoluteString] length]]; + } else { + // NOTE: [URL relativeString] would return the same value as `absoluteString` if URL is not relative to a baseURL + NSString *query = [URL query]; + NSString *pathWithPrevervedTrailingSlash = [CFBridgingRelease(CFURLCopyPath((CFURLRef)URL)) stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; + return (query && [query length]) ? [NSString stringWithFormat:@"%@?%@", pathWithPrevervedTrailingSlash, query] : pathWithPrevervedTrailingSlash; + } +} + +NSIndexSet *RKStatusCodesOfResponsesWithOptionalBodies() +{ + NSMutableIndexSet *statusCodes = [NSMutableIndexSet indexSet]; + [statusCodes addIndex:201]; + [statusCodes addIndex:202]; + [statusCodes addIndex:204]; + [statusCodes addIndex:205]; + [statusCodes addIndex:304]; + return statusCodes; +} diff --git a/Pods/RestKit/Code/ObjectMapping/RKMapperOperation.h b/Pods/RestKit/Code/ObjectMapping/RKMapperOperation.h new file mode 100644 index 0000000..94489d0 --- /dev/null +++ b/Pods/RestKit/Code/ObjectMapping/RKMapperOperation.h @@ -0,0 +1,256 @@ +// +// RKMapperOperation.h +// RestKit +// +// Created by Blake Watters on 5/6/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import <Foundation/Foundation.h> +#import "RKObjectMapping.h" +#import "RKMappingOperation.h" +#import "RKMappingResult.h" +#import "RKMappingOperationDataSource.h" +#import "RKErrors.h" + +@protocol RKMapperOperationDelegate; + +/** + `RKMapperOperation` is an `NSOperation` subclass that implements object mapping for opaque object representations. Given a dictionary or an array of dictionaries that represent objects and a dictionary describing how to map the representations, the mapper will transform the source representations into `NSObject` or `NSManagedObject` instances. Mapper operations are used to map object representations from Foundation object representations, such as those deserialized from a JSON or XML document or loaded from a file. Not all the mappings specified in the mappings dictionary are required to match content in the source object for the operation to succeed. However, if none of the mappable key paths in the mappings dictionary match the source object then the operation will fail and the `error` property will be set to an `NSError` object in the `RKErrorDomain` domain with an error code value of `RKMappingErrorNotFound`. + + `RKMapperOperation` does not actually perform any mapping work. Instead, it instantiates and starts `RKMappingOperation` objects to process the mappable object representations it encounters. + + `RKMapperOperation` is a non-concurrent operation. Execution will occur synchronously on the calling thread unless the operation is enqueued onto an `NSOperationQueue`. + + ## Mappings Dictionary + + The mappings dictionary describes how to object map the source object. The keys of the dictionary are key paths into the `representation` and the values are `RKMapping` objects describing how to map the representations at the corresponding key path. This dictionary based approach enables a single document to contain an arbitrary number of object representations that can be mapped independently. Consider the following example JSON structure: + + { "tags": [ "hacking", "phreaking" ], "authors": [ "Captain Crunch", "Emmanuel Goldstein" ], "magazine": { "title": "2600 The Hacker Quarterly" } } + + Each key in the document could be mapped independently by providing a mapping for the key paths: + + RKObjectMapping *tagMapping = [RKObjectMapping mappingForClass:[Tag class]]; + RKObjectMapping *authorMapping = [RKObjectMapping mappingForClass:[Author class]]; + RKObjectMapping *magazineMapping = [RKObjectMapping mappingForClass:[Magazine class]]; + NSDictionary *mappingsDictionary = @{ @"tag": tagMapping, @"author": authorMapping, @"magazine": magazine }; + + Note that the keys of the dictionary are **key paths**. Deeply nested content can be mapped by specifying the full key path as the key of the mappings dictionary. + + ### Mapping the Root Object Representation + + A mapping set for the key `[NSNull null]` value has special significance to the mapper operation. When a mapping is encountered with the a null key, the entire `representation` is processed using the given mapping. This provides support for mapping content that does not have an outer nesting attribute. + + Note that it is possible to map the same representation with multiple mappings, including a combination of a root key mapping and nested keypaths. + + ## Data Source + + The data source is used to instantiate new objects or find existing objects to be updated during the mapping process. The object set as the `mappingOperationDataSource` will be set as the `dataSource` for the `RKMappingOperation` objects created by the mapper. + + ## Target Object + + If a `targetObject` is configured on the mapper operation, all mapping work on the `representation` will target the specified object. For transient `NSObject` mappings, this ensures that the properties of an existing object are updated rather than an new object being created for the mapped representation. If an array of representations is being processed and a `targetObject` is provided, it must be a mutable collection object else an exception will be raised. + + ## Metadata Mapping + + The `RKMapperOperation` class provides support for metadata mapping provided to the operation via the `mappingMetadata` property. This dictionary is made available to all `RKMappingOperation` objects executed by the receiver to process the representation being mapped. In addition to any user supplied metadata, the mapper operation makes the following metadata key paths available for mapping: + + 1. `@metadata.mapping.rootKeyPath` - An object specifying the root key path at which the current representation is nested within the source representation. This will correspond to a key in the `mappingsDictionary` and is typically an `NSString`, but can be `[NSNull null]` if the representation being mapped is at the root. + 1. `@metadata.mapping.collectionIndex` - An `NSNumber` object specifying the index of the current object within a collection being mapped. This key is only available if the current representation exists within a collection. + + Please refer to the documentation accompanying `RKMappingOperation` for more details on metadata mapping. + + ## Core Data + + `RKMapperOperation` supports mapping to Core Data target entities. To do so, it must be configured with an `RKManagedObjectMappingOperationDataSource` object as the data source. + */ +@interface RKMapperOperation : NSOperation + +///-------------------------------------- +/// @name Initializing a Mapper Operation +///-------------------------------------- + +/** + Initializes the operation with a source object and a mappings dictionary. + + @param representation An `NSDictionary` or `NSArray` of `NSDictionary` object representations to be mapped into local domain objects. + @param mappingsDictionary An `NSDictionary` wherein the keys are mappable key paths in `object` and the values are `RKMapping` objects specifying how the representations at its key path are to be mapped. + @return The receiver, initialized with the given object and and dictionary of key paths to mappings. + */ +- (instancetype)initWithRepresentation:(id)representation mappingsDictionary:(NSDictionary *)mappingsDictionary NS_DESIGNATED_INITIALIZER; + +///------------------------------------------ +/// @name Accessing Mapping Result and Errors +///------------------------------------------ + +/** + The error, if any, that occurred during the mapping process. + */ +@property (nonatomic, strong, readonly) NSError *error; + +/** + The result of the mapping process. A `nil` value indicates that no mappable object representations were found and no mapping was performed. + */ +@property (nonatomic, strong, readonly) RKMappingResult *mappingResult; + +/** + Returns a dictionary containing information about the mappings applied during the execution of the operation. The keys of the dictionary are keyPaths into the `mappingResult` for values that were mapped and the values are the corresponding `RKPropertyMapping` objects used to perform the mapping. + */ +@property (nonatomic, readonly) NSDictionary *mappingInfo; + +///------------------------------------- +/// @name Managing Mapping Configuration +///------------------------------------- + +/** + The representation of one or more objects against which the mapping is performed. + + Either an `NSDictionary` or an `NSArray` of `NSDictionary` objects. + */ +@property (nonatomic, strong, readonly) id representation; + +/** + A dictionary of key paths to `RKMapping` objects specifying how object representations in the `representation` are to be mapped. + + Please see the above discussion for in-depth details about the mappings dictionary. + */ +@property (nonatomic, strong, readonly) NSDictionary *mappingsDictionary; + +/** + The target object of the mapper. When configured, all object mapping will target the specified object. + + Please see the above discussion for details about target objects. + */ +@property (nonatomic, weak) id targetObject; + +/** + The data source for the underlying `RKMappingOperation` objects that perform the mapping work configured by the mapper. + */ +@property (nonatomic, strong) id<RKMappingOperationDataSource> mappingOperationDataSource; + +/** + The delegate for the mapper operation. + */ +@property (nonatomic, weak) id<RKMapperOperationDelegate> delegate; + +/** + A dictionary of metadata that is available for mappping by any mapping operation started by the receiver. + */ +@property (nonatomic, copy) NSDictionary *metadata; + +///------------------------------ +/// @name Executing the Operation +///------------------------------ + +/** + Executes the mapper operation to completion. + + @param error A pointer to an `NSError` object to set in the event an error occurs during execution. + @return A Boolean value that indicates if the operation completed successfully. + */ +- (BOOL)execute:(NSError **)error; + +@end + +///-------------------------------- +/// @name Mapper Operation Delegate +///-------------------------------- + +/** + Objects wishing to act as the delegate for `RKMapperOperation` objects must adopt the `RKMapperOperationDelegate` protocol. The protocol provides a rich set of optional callback methods that provides insight into the lifecycle of a mapper operation. + */ +@protocol RKMapperOperationDelegate <NSObject> + +@optional + +///----------------------------- +/// @name Tracking Mapper Status +///----------------------------- + +/** + Tells the delegate that the mapper operation is about to start mapping. + + @param mapper The mapper operation that is about to start mapping. + */ +- (void)mapperWillStartMapping:(RKMapperOperation *)mapper; + +/** + Tells the delegate that the mapper has finished. + + @param mapper The mapper operation that has finished mapping. + */ +- (void)mapperDidFinishMapping:(RKMapperOperation *)mapper; + +/** + Tells the delegate that the mapper has been cancelled. + + @param mapper The mapper operation that was cancelled. + */ +- (void)mapperDidCancelMapping:(RKMapperOperation *)mapper; + +///------------------------------- +/// @name Key Path Search Messages +///------------------------------- + +/** + Tells the delegate that the mapper has found one or more mappable object representations at a key path specified in the `mappingsDictionary`. + + @param mapper The mapper operation performing the mapping. + @param dictionaryOrArrayOfDictionaries The `NSDictictionary` or `NSArray` of `NSDictionary` object representations that was found at the `keyPath`. + @param keyPath The key path that the representation was read from in the `representation`. If the `keyPath` was `[NSNull null]` in the `mappingsDictionary`, it will be given as `nil` to the delegate. + */ +- (void)mapper:(RKMapperOperation *)mapper didFindRepresentationOrArrayOfRepresentations:(id)dictionaryOrArrayOfDictionaries atKeyPath:(NSString *)keyPath; + +/** + Tells the delegate that the mapper failed to find any mappable object representations at a key path specified in the `mappingsDictionary`. + + @param mapper The mapper operation performing the mapping. + @param keyPath The key path that was searched for a mappable object representation. + */ +- (void)mapper:(RKMapperOperation *)mapper didNotFindRepresentationOrArrayOfRepresentationsAtKeyPath:(NSString *)keyPath; + +///---------------------------------------------- +/// @name Tracking Child Mapping Operation Status +///---------------------------------------------- + +/** + Tells the delegate that the mapper is about to start a mapping operation to map a representation found in the `representation`. + + @param mapper The mapper operation performing the mapping. + @param mappingOperation The mapping operation that is about to be started. + @param keyPath The key path that was mapped. A `nil` key path indicates that the mapping matched the entire `representation`. + */ +- (void)mapper:(RKMapperOperation *)mapper willStartMappingOperation:(RKMappingOperation *)mappingOperation forKeyPath:(NSString *)keyPath; + +/** + Tells the delegate that a mapping operation that was started by the mapper has finished executing. + + @param mapper The mapper operation performing the mapping. + @param mappingOperation The mapping operation that has finished. + @param keyPath The key path that was mapped. A `nil` key path indicates that the mapping matched the entire `representation`. + */ +- (void)mapper:(RKMapperOperation *)mapper didFinishMappingOperation:(RKMappingOperation *)mappingOperation forKeyPath:(NSString *)keyPath; + +/** + Tells the delegate that a mapping operation that was started by the mapper has failed with an error. + + @param mapper The mapper operation performing the mapping. + @param mappingOperation The mapping operation that has failed. + @param keyPath The key path that was mapped. A `nil` key path indicates that the mapping matched the entire `representation`. + @param error The error that occurred during the execution of the mapping operation. + */ +- (void)mapper:(RKMapperOperation *)mapper didFailMappingOperation:(RKMappingOperation *)mappingOperation forKeyPath:(NSString *)keyPath withError:(NSError *)error; + +@end diff --git a/Pods/RestKit/Code/ObjectMapping/RKMapperOperation.m b/Pods/RestKit/Code/ObjectMapping/RKMapperOperation.m new file mode 100644 index 0000000..db0cdcb --- /dev/null +++ b/Pods/RestKit/Code/ObjectMapping/RKMapperOperation.m @@ -0,0 +1,446 @@ +// +// RKMapperOperation.m +// RestKit +// +// Created by Blake Watters on 5/6/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKMapperOperation.h" +#import "RKMapperOperation_Private.h" +#import "RKObjectMapping.h" +#import "RKObjectMappingOperationDataSource.h" +#import "RKMappingErrors.h" +#import "RKDynamicMapping.h" +#import "RKLog.h" +#import "RKDictionaryUtilities.h" + +NSString * const RKMappingErrorKeyPathErrorKey = @"keyPath"; + +// Set Logging Component +#undef RKLogComponent +#define RKLogComponent RKlcl_cRestKitObjectMapping + +static NSString *RKDelegateKeyPathFromKeyPath(NSString *keyPath) +{ + return ([keyPath isEqual:[NSNull null]]) ? nil : keyPath; +} + + +static NSString *RKFailureReasonErrorStringForMappingNotFoundError(id representation, NSDictionary *mappingsDictionary) +{ + NSMutableString *failureReason = [NSMutableString string]; + [failureReason appendFormat:@"The mapping operation was unable to find any nested object representations at the key paths searched: %@", [[[mappingsDictionary allKeys] sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)] componentsJoinedByString:@", "]]; + if ([representation respondsToSelector:@selector(allKeys)]) { + [failureReason appendFormat:@"\nThe representation inputted to the mapper was found to contain nested object representations at the following key paths: %@", [[[representation allKeys] sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)] componentsJoinedByString:@", "]]; + } + [failureReason appendFormat:@"\nThis likely indicates that you have misconfigured the key paths for your mappings."]; + return failureReason; +} + +// Duplicating interface from `RKMappingOperation.m` +@interface RKMappingSourceObject : NSObject +- (instancetype)initWithObject:(id)object parentObject:(id)parentObject rootObject:(id)rootObject metadata:(NSArray *)metadata; +@end + +@interface RKMappingOperation (Private) +@property (nonatomic, readwrite, getter=isNewDestinationObject) BOOL newDestinationObject; +@end + +@interface RKMapperMetadata : NSObject +@property NSUInteger collectionIndex; +@property NSString *rootKeyPath; +@end + +@implementation RKMapperMetadata +- (id)valueForUndefinedKey:(NSString *)key { return nil; } +@end + +@interface RKMapperOperation () + +@property (nonatomic, strong, readwrite) NSError *error; +@property (nonatomic, strong, readwrite) RKMappingResult *mappingResult; +@property (nonatomic, strong) NSMutableArray *mappingErrors; +@property (nonatomic, strong) id representation; +@property (nonatomic, strong, readwrite) NSDictionary *mappingsDictionary; +@property (nonatomic, strong) NSMutableDictionary *mutableMappingInfo; +@end + +@implementation RKMapperOperation + +- (instancetype)initWithRepresentation:(id)representation mappingsDictionary:(NSDictionary *)mappingsDictionary; +{ + self = [super init]; + if (self) { + self.representation = representation; + self.mappingsDictionary = mappingsDictionary; + self.mappingOperationDataSource = [RKObjectMappingOperationDataSource new]; + } + + return self; +} + +- (NSDictionary *)mappingInfo +{ + return self.mutableMappingInfo; +} + +#pragma mark - Errors + +- (NSArray *)errors +{ + return [NSArray arrayWithArray:self.mappingErrors]; +} + +- (void)addError:(NSError *)error +{ + NSAssert(error, @"Cannot add a nil error"); + [self.mappingErrors addObject:error]; +} + +- (void)addErrorWithCode:(RKMappingErrorCode)errorCode message:(NSString *)errorMessage keyPath:(NSString *)keyPath userInfo:(NSDictionary *)otherInfo +{ + NSMutableDictionary *userInfo = [NSMutableDictionary dictionaryWithObjectsAndKeys: + errorMessage, NSLocalizedDescriptionKey, + keyPath ? keyPath : [NSNull null], RKMappingErrorKeyPathErrorKey, + nil]; + [userInfo addEntriesFromDictionary:otherInfo]; + NSError *error = [NSError errorWithDomain:RKErrorDomain code:errorCode userInfo:userInfo]; + [self addError:error]; + self.error = error; +} + +- (void)addErrorForUnmappableKeyPath:(NSString *)keyPath +{ + NSString *errorMessage = [NSString stringWithFormat:@"Could not find an object mapping for keyPath: '%@'", keyPath]; + [self addErrorWithCode:RKMappingErrorNotFound message:errorMessage keyPath:keyPath userInfo:nil]; +} + +- (BOOL)isNullCollection:(id)object +{ + // The purpose of this method is to guard against the case where we perform valueForKeyPath: on an array + // and it returns NSNull for each element in the array. + + // We consider an empty array/dictionary mappable, but a collection that contains only NSNull + // values is unmappable + if ([object respondsToSelector:@selector(objectForKey:)]) { + return NO; + } + + if ([object respondsToSelector:@selector(countForObject:)] && [object count] > 0) { + if ([object countForObject:[NSNull null]] == [object count]) { + RKLogDebug(@"Found a collection containing only `NSNull` values, considering the collection unmappable..."); + return YES; + } + } + + return NO; +} + +#pragma mark - Mapping Primitives + +// Maps a singular object representation +- (id)mapRepresentation:(id)representation atKeyPath:(NSString *)keyPath usingMapping:(RKMapping *)mapping +{ + NSAssert([representation respondsToSelector:@selector(setValue:forKeyPath:)], @"Expected self.object to be KVC compliant"); + id destinationObject = nil; + BOOL isNewObject = NO; + + if (self.targetObject) { + destinationObject = self.targetObject; + RKObjectMapping *objectMapping = nil; + if ([mapping isKindOfClass:[RKDynamicMapping class]]) { + objectMapping = [(RKDynamicMapping *)mapping objectMappingForRepresentation:representation]; + } else if ([mapping isKindOfClass:[RKObjectMapping class]]) { + objectMapping = (RKObjectMapping *)mapping; + } else { + NSAssert(objectMapping, @"Encountered unknown mapping type '%@'", NSStringFromClass([mapping class])); + } + + if (NO == [[self.targetObject class] isSubclassOfClass:objectMapping.objectClass]) { + if ([_mappingsDictionary count] == 1) { + NSString *errorMessage = [NSString stringWithFormat: + @"Expected an object mapping for class of type '%@', provider returned one for '%@'", + NSStringFromClass([self.targetObject class]), NSStringFromClass(objectMapping.objectClass)]; + [self addErrorWithCode:RKMappingErrorTypeMismatch message:errorMessage keyPath:keyPath userInfo:nil]; + return nil; + } else { + // There is more than one mapping present. We are likely mapping secondary key paths to new objects + destinationObject = [self objectForRepresentation:representation withMapping:mapping]; + isNewObject = YES; + } + } + } else { + destinationObject = [self objectForRepresentation:representation withMapping:mapping]; + isNewObject = YES; + } + + if (mapping && destinationObject) { + NSArray *metadataList = [NSArray arrayWithObjects:@{ @"mapping": @{ @"rootKeyPath": keyPath } }, self.metadata, nil]; + BOOL success = [self mapRepresentation:representation toObject:destinationObject isNew:isNewObject atKeyPath:keyPath usingMapping:mapping metadataList:metadataList]; + if (success) { + return destinationObject; + } + } else { + // Attempted to map an object but couldn't find a mapping for the keyPath + [self addErrorForUnmappableKeyPath:keyPath]; + return nil; + } + + return nil; +} + +// Map a collection of object representations +- (NSArray *)mapRepresentations:(id)representations atKeyPath:(NSString *)keyPath usingMapping:(RKMapping *)mapping +{ + NSAssert(representations != nil, @"Cannot map without an collection of mappable objects"); + NSAssert(mapping != nil, @"Cannot map without a mapping to consult"); + + NSArray *objectsToMap = representations; + if (mapping.forceCollectionMapping) { + // If we have forced mapping of a dictionary, map each subdictionary + if ([representations isKindOfClass:[NSDictionary class]]) { + RKLogDebug(@"Collection mapping forced for NSDictionary, mapping each key/value independently..."); + objectsToMap = [NSMutableArray arrayWithCapacity:[representations count]]; + for (id key in representations) { + NSDictionary *dictionaryToMap = @{key: [representations valueForKey:key]}; + [(NSMutableArray *)objectsToMap addObject:dictionaryToMap]; + } + } else { + RKLogWarning(@"Collection mapping forced but representations is of type '%@' rather than NSDictionary", NSStringFromClass([representations class])); + } + } + + RKMapperMetadata *mappingData = [RKMapperMetadata new]; + mappingData.rootKeyPath = keyPath; + NSDictionary *metadata = @{ @"mapping": mappingData }; + NSArray *metadataList = [NSArray arrayWithObjects:metadata, self.metadata, nil]; + NSMutableArray *mappedObjects = [NSMutableArray arrayWithCapacity:[representations count]]; + [objectsToMap enumerateObjectsUsingBlock:^(id mappableObject, NSUInteger index, BOOL *stop) { + id destinationObject = [self objectForRepresentation:mappableObject withMapping:mapping]; + if (destinationObject) { + mappingData.collectionIndex = index; + BOOL success = [self mapRepresentation:mappableObject toObject:destinationObject isNew:YES atKeyPath:keyPath usingMapping:mapping metadataList:metadataList]; + if (success) [mappedObjects addObject:destinationObject]; + } + *stop = [self isCancelled]; + }]; + + return mappedObjects; +} + +// The workhorse of this entire process. Emits object loading operations +- (BOOL)mapRepresentation:(id)mappableObject toObject:(id)destinationObject isNew:(BOOL)newDestination atKeyPath:(NSString *)keyPath usingMapping:(RKMapping *)mapping metadataList:(NSArray *)metadataList +{ + NSAssert(destinationObject != nil, @"Cannot map without a target object to assign the results to"); + NSAssert(mappableObject != nil, @"Cannot map without a collection of attributes"); + NSAssert(mapping != nil, @"Cannot map without an mapping"); + + RKLogDebug(@"Asked to map source object %@ with mapping %@", mappableObject, mapping); + + RKMappingOperation *mappingOperation = [[RKMappingOperation alloc] initWithSourceObject:mappableObject destinationObject:destinationObject mapping:mapping metadataList:metadataList]; + mappingOperation.dataSource = self.mappingOperationDataSource; + mappingOperation.newDestinationObject = newDestination; + if ([self.delegate respondsToSelector:@selector(mapper:willStartMappingOperation:forKeyPath:)]) { + [self.delegate mapper:self willStartMappingOperation:mappingOperation forKeyPath:RKDelegateKeyPathFromKeyPath(keyPath)]; + } + [mappingOperation start]; + if (mappingOperation.error) { + if ([self.delegate respondsToSelector:@selector(mapper:didFailMappingOperation:forKeyPath:withError:)]) { + [self.delegate mapper:self didFailMappingOperation:mappingOperation forKeyPath:RKDelegateKeyPathFromKeyPath(keyPath) withError:mappingOperation.error]; + } + [self addError:mappingOperation.error]; + + return NO; + } else { + if ([self.delegate respondsToSelector:@selector(mapper:didFinishMappingOperation:forKeyPath:)]) { + [self.delegate mapper:self didFinishMappingOperation:mappingOperation forKeyPath:RKDelegateKeyPathFromKeyPath(keyPath)]; + } + + if (mappingOperation.mappingInfo) { + id infoKey = keyPath ?: [NSNull null]; + NSMutableArray *infoForKeyPath = (self.mutableMappingInfo)[infoKey]; + if (infoForKeyPath) { + [infoForKeyPath addObject:mappingOperation.mappingInfo]; + } else { + infoForKeyPath = [NSMutableArray arrayWithObject:mappingOperation.mappingInfo]; + [self.mutableMappingInfo setValue:infoForKeyPath forKey:infoKey]; + } + } + + return YES; + } +} + +- (id)objectForRepresentation:(id)representation withMapping:(RKMapping *)mapping +{ + NSAssert([mapping isKindOfClass:[RKMapping class]], @"Expected an RKMapping object"); + NSAssert(self.mappingOperationDataSource, @"Cannot find or instantiate objects without a data source"); + + RKObjectMapping *objectMapping = nil; + if ([mapping isKindOfClass:[RKDynamicMapping class]]) { + objectMapping = [(RKDynamicMapping *)mapping objectMappingForRepresentation:representation]; + if (! objectMapping) { + RKLogDebug(@"Mapping %@ declined mapping for representation %@: returned nil objectMapping", mapping, representation); + } + } else if ([mapping isKindOfClass:[RKObjectMapping class]]) { + objectMapping = (RKObjectMapping *)mapping; + } else { + NSAssert(objectMapping, @"Encountered unknown mapping type '%@'", NSStringFromClass([mapping class])); + } + + if (objectMapping) { + id object = nil; + if ([self.mappingOperationDataSource respondsToSelector:@selector(mappingOperation:targetObjectForMapping:inRelationship:)]) + { + object = [self.mappingOperationDataSource mappingOperation:nil targetObjectForMapping:objectMapping inRelationship:nil]; + } + if (object == nil) + { + // Ensure that we are working with a dictionary when we call down into the data source + NSDictionary *representationDictionary = [representation isKindOfClass:[NSDictionary class]] ? representation : @{ [NSNull null]: representation }; + id mappingSourceObject = [[RKMappingSourceObject alloc] initWithObject:representationDictionary parentObject:nil rootObject:representation metadata:self.metadata? @[self.metadata] : nil]; + object = [self.mappingOperationDataSource mappingOperation:nil targetObjectForRepresentation:mappingSourceObject withMapping:objectMapping inRelationship:nil]; + } + return object; + } + + return nil; +} + +- (id)mapRepresentationOrRepresentations:(id)mappableValue atKeyPath:(NSString *)keyPath usingMapping:(RKMapping *)mapping +{ + id mappingResult; + if (mapping.forceCollectionMapping || [mappableValue isKindOfClass:[NSArray class]] || [mappableValue isKindOfClass:[NSSet class]]) { + RKLogDebug(@"Found mappable collection at keyPath '%@': %@", keyPath, mappableValue); + mappingResult = [self mapRepresentations:mappableValue atKeyPath:keyPath usingMapping:mapping]; + } else { + RKLogDebug(@"Found mappable data at keyPath '%@': %@", keyPath, mappableValue); + mappingResult = [self mapRepresentation:mappableValue atKeyPath:keyPath usingMapping:mapping]; + } + + return mappingResult; +} + +#pragma mark - + +- (NSMutableDictionary *)mapSourceRepresentationWithMappingsDictionary:(NSDictionary *)mappingsByKeyPath +{ + BOOL foundMappable = NO; + NSMutableDictionary *results = [NSMutableDictionary dictionary]; + for (NSString *keyPath in mappingsByKeyPath) { + if ([self isCancelled]) return nil; + + @autoreleasepool { + id mappingResult = nil; + id nestedRepresentation = nil; + + RKLogTrace(@"Examining keyPath '%@' for mappable content...", keyPath); + + if ([keyPath isEqual:[NSNull null]] || [keyPath isEqualToString:@""]) { + nestedRepresentation = self.representation; + } else { + nestedRepresentation = [self.representation valueForKeyPath:keyPath]; + } + + // Not found... + if (nestedRepresentation == nil || nestedRepresentation == [NSNull null] || [self isNullCollection:nestedRepresentation]) { + RKLogDebug(@"Found unmappable value at keyPath: %@", keyPath); + + if ([self.delegate respondsToSelector:@selector(mapper:didNotFindRepresentationOrArrayOfRepresentationsAtKeyPath:)]) { + [self.delegate mapper:self didNotFindRepresentationOrArrayOfRepresentationsAtKeyPath:RKDelegateKeyPathFromKeyPath(keyPath)]; + } + + continue; + } + + // Found something to map + foundMappable = YES; + RKMapping *mapping = mappingsByKeyPath[keyPath]; + if ([self.delegate respondsToSelector:@selector(mapper:didFindRepresentationOrArrayOfRepresentations:atKeyPath:)]) { + [self.delegate mapper:self didFindRepresentationOrArrayOfRepresentations:nestedRepresentation atKeyPath:RKDelegateKeyPathFromKeyPath(keyPath)]; + } + + mappingResult = [self mapRepresentationOrRepresentations:nestedRepresentation atKeyPath:keyPath usingMapping:mapping]; + + if (mappingResult) { + results[keyPath] = mappingResult; + } + } + } + + if (NO == foundMappable) return nil; + return results; +} + +- (void)cancel +{ + [super cancel]; + RKLogDebug(@"%@:%p received `cancel` message: cancelling mapping...", [self class], self); + + if ([self.delegate respondsToSelector:@selector(mapperDidCancelMapping:)]) { + [self.delegate mapperDidCancelMapping:self]; + } +} + +- (void)main +{ + NSAssert(self.representation != nil, @"Cannot perform object mapping without a source object to map from"); + NSAssert(self.mappingsDictionary, @"Cannot perform object mapping without a dictionary of mappings"); + + if ([self isCancelled]) return; + self.mutableMappingInfo = [NSMutableDictionary dictionary]; + self.mappingErrors = [NSMutableArray new]; + + RKLogDebug(@"Executing mapping operation for representation: %@\n and targetObject: %@", self.representation, self.targetObject); + + if ([self.delegate respondsToSelector:@selector(mapperWillStartMapping:)]) { + [self.delegate mapperWillStartMapping:self]; + } + + // Perform the mapping + BOOL foundMappable = NO; + NSMutableDictionary *results = [self mapSourceRepresentationWithMappingsDictionary:self.mappingsDictionary]; + if ([self isCancelled]) return; + foundMappable = (results != nil); + + // If we found nothing eligible for mapping in the content, add an unmappable key path error and fail mapping + // If the content is empty, we don't consider it an error + BOOL isEmpty = [self.representation respondsToSelector:@selector(count)] && ([self.representation count] == 0); + if (foundMappable == NO && !isEmpty) { + NSMutableDictionary *userInfo = [@{ NSLocalizedDescriptionKey: NSLocalizedString(@"No mappable object representations were found at the key paths searched.", nil), + NSLocalizedFailureReasonErrorKey: RKFailureReasonErrorStringForMappingNotFoundError(self.representation, self.mappingsDictionary), + RKMappingErrorKeyPathErrorKey: [NSNull null], + RKDetailedErrorsKey: self.errors} mutableCopy]; + NSError *compositeError = [[NSError alloc] initWithDomain:RKErrorDomain code:RKMappingErrorNotFound userInfo:userInfo]; + self.error = compositeError; + } else { + if (results) self.mappingResult = [[RKMappingResult alloc] initWithDictionary:results]; + } + + RKLogDebug(@"Finished performing object mapping. Results: %@", results); + if ([self.delegate respondsToSelector:@selector(mapperDidFinishMapping:)]) { + [self.delegate mapperDidFinishMapping:self]; + } +} + +- (BOOL)execute:(NSError **)error +{ + [self start]; + if (error) *error = self.error; + return self.mappingResult != nil; +} + +@end diff --git a/Pods/RestKit/Code/ObjectMapping/RKMapperOperation_Private.h b/Pods/RestKit/Code/ObjectMapping/RKMapperOperation_Private.h new file mode 100644 index 0000000..0804dcf --- /dev/null +++ b/Pods/RestKit/Code/ObjectMapping/RKMapperOperation_Private.h @@ -0,0 +1,28 @@ +// +// RKMapperOperation_Private.h +// RestKit +// +// Created by Blake Watters on 5/9/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +@interface RKMapperOperation (Private) + +- (id)mapRepresentation:(id)mappableObject atKeyPath:(NSString *)keyPath usingMapping:(RKMapping *)mapping; +- (NSArray *)mapRepresentations:(NSArray *)mappableObjects atKeyPath:(NSString *)keyPath usingMapping:(RKMapping *)mapping; +- (BOOL)mapRepresentation:(id)mappableObject toObject:(id)destinationObject isNew:(BOOL)isNew atKeyPath:(NSString *)keyPath usingMapping:(RKMapping *)mapping metadataList:(NSArray *)metadata; +- (id)objectForRepresentation:(id)representation withMapping:(RKMapping *)mapping; + +@end diff --git a/Pods/RestKit/Code/ObjectMapping/RKMapping.h b/Pods/RestKit/Code/ObjectMapping/RKMapping.h new file mode 100644 index 0000000..b3a969d --- /dev/null +++ b/Pods/RestKit/Code/ObjectMapping/RKMapping.h @@ -0,0 +1,62 @@ +// +// RKMapping.h +// RestKit +// +// Created by Blake Watters on 7/31/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import <Foundation/Foundation.h> + +/** + `RKMapping` is an abstract class for objects defining RestKit object mappings. Its interface is common to all object mapping classes, including its concrete subclasses `RKObjectMapping` and `RKDynamicMapping`. + */ +@interface RKMapping : NSObject + +///--------------------------------- +/// @name Forcing Collection Mapping +///--------------------------------- + +/** + Forces the mapper to treat the mapped keyPath as a collection even if it does not return an array or a set of objects. This permits mapping where a dictionary identifies a collection of objects. + + When enabled, each key/value pair in the resolved dictionary will be mapped as a separate entity. This is useful when you have a JSON structure similar to: + + { "users": { + "blake": { "id": 1234, "email": "blake@restkit.org" }, + "rachit": { "id": 5678, "email": "rachit@restkit.org" } + } + } + + By enabling `forceCollectionMapping`, RestKit will map "blake" => attributes and "rachit" => attributes as independent objects. This can be combined with `mapKeyOfNestedDictionaryToAttribute:` to properly map these sorts of structures. + + @default `NO` + @see `mapKeyOfNestedDictionaryToAttribute` + */ +@property (nonatomic, assign) BOOL forceCollectionMapping; + + +///------------------------- +/// @name Comparing Mappings +///------------------------- + +/** + Returns `YES` if the receiver and the specified mapping are considered equivalent. + + **NOTE**: Must be implemented in subclass. + */ +- (BOOL)isEqualToMapping:(RKMapping *)otherMapping; + +@end diff --git a/Pods/RestKit/Code/ObjectMapping/RKMapping.m b/Pods/RestKit/Code/ObjectMapping/RKMapping.m new file mode 100644 index 0000000..9f60f3b --- /dev/null +++ b/Pods/RestKit/Code/ObjectMapping/RKMapping.m @@ -0,0 +1,22 @@ +// +// RKMapping.m +// RestKit +// +// Created by Blake Watters on 2/15/12. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// + +#import "RKMapping.h" + +@implementation RKMapping + +@synthesize forceCollectionMapping; + +- (BOOL)isEqualToMapping:(RKMapping *)otherMapping +{ + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:[NSString stringWithFormat:@"You must override %@ in a subclass", NSStringFromSelector(_cmd)] + userInfo:nil]; +} + +@end diff --git a/Pods/RestKit/Code/ObjectMapping/RKMappingErrors.h b/Pods/RestKit/Code/ObjectMapping/RKMappingErrors.h new file mode 100644 index 0000000..794e703 --- /dev/null +++ b/Pods/RestKit/Code/ObjectMapping/RKMappingErrors.h @@ -0,0 +1,37 @@ +// +// RKMappingErrors.h +// RestKit +// +// Created by Blake Watters on 5/31/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKErrors.h" + +typedef UInt32 RKMappingErrorCode; +enum { + RKMappingErrorNotFound = 1001, // No mapping found + RKMappingErrorTypeMismatch = 1002, // Target class and object mapping are in disagreement + RKMappingErrorUnmappableRepresentation = 1003, // No values were found at the key paths of any attribute or relationship mappings in the given representation + RKMappingErrorFromMappingResult = 1004, // The error was returned from the mapping result + RKMappingErrorValidationFailure = 1005, // Generic error code for use when constructing validation errors + RKMappingErrorUnableToDetermineMapping = 1006, // The mapping operation was unable to obtain a concrete object mapping from a given dynamic mapping + RKMappingErrorNilDestinationObject = 1007, // The mapping operation failed due to a nil destination object. + RKMappingErrorNilManagedObjectCache = 1008, // A managed object cache is required to satisfy the mapping, but none was given. + RKMappingErrorMappingDeclined = 1009, // Mapping was declined by a callback. + RKMappingErrorInvalidAssignmentPolicy = 1010, // The assignment policy for the relationship is invalid. +}; + +extern NSString * const RKMappingErrorKeyPathErrorKey; // The key path the error is associated with diff --git a/Pods/RestKit/Code/ObjectMapping/RKMappingOperation.h b/Pods/RestKit/Code/ObjectMapping/RKMappingOperation.h new file mode 100644 index 0000000..7c5d782 --- /dev/null +++ b/Pods/RestKit/Code/ObjectMapping/RKMappingOperation.h @@ -0,0 +1,390 @@ +// +// RKMappingOperation.h +// RestKit +// +// Created by Blake Watters on 4/30/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKObjectMapping.h" +#import "RKAttributeMapping.h" + +@class RKMappingOperation, RKDynamicMapping, RKConnectionDescription, RKMappingInfo; +@protocol RKMappingOperationDataSource; + +/** + Objects acting as the delegate for `RKMappingOperation` objects must adopt the `RKMappingOperationDelegate` protocol. These methods enable the delegate to be notified of events such as the application of attribute and relationship mappings during a mapping operation. + */ +@protocol RKMappingOperationDelegate <NSObject> + +///--------------------------------------- +/// @name Tracking Property Mapping Events +///--------------------------------------- + +@optional + +/** + Tells the delegate that an attribute or relationship mapping was found for a given key path within the data being mapped. + + @param operation The object mapping operation being performed. + @param keyPath The key path in the source object for which the mapping is to be applied. + @param value The value that was found at the given key path in the source object representation. + @param propertyMapping The `RKAttributeMapping` or `RKRelationshipMapping` for which the mappable value was found within the source object representation. + */ +- (void)mappingOperation:(RKMappingOperation *)operation didFindValue:(id)value forKeyPath:(NSString *)keyPath mapping:(RKPropertyMapping *)propertyMapping; + +/** + Tells the delegate that no attribute or relationships mapping was found for a given key path within the data being mapped. + + @param operation The object mapping operation being performed. + @param keyPath The key path in the source object for which no mappable value was found. + @param propertyMapping The `RKAttributeMapping` or `RKRelationshipMapping` for which no mappable value could be found within the source object representation. + */ +- (void)mappingOperation:(RKMappingOperation *)operation didNotFindValueForKeyPath:(NSString *)keyPath mapping:(RKPropertyMapping *)propertyMapping; + +/** + Asks the delegate if the mapping operation should set a value for a given key path with an attribute or relationship mapping. This method is invoked before the value is set. If the delegate does not implement this method, then the mapping operation will determine if the value should be set by comparing the current property value with the new property value. + + @param operation The object mapping operation being performed. + @param value A new value that was set on the destination object. + @param keyPath The key path in the destination object for which a new value has been set. + @param propertyMapping The `RKAttributeMapping` or `RKRelationshipMapping` found for the key path. + @return `YES` if the operation should set the proposed value for the key path, else `NO`. + */ +- (BOOL)mappingOperation:(RKMappingOperation *)operation shouldSetValue:(id)value forKeyPath:(NSString *)keyPath usingMapping:(RKPropertyMapping *)propertyMapping; + +/** + Tells the delegate that the mapping operation has set a value for a given key path with an attribute or relationship mapping. + + @param operation The object mapping operation being performed. + @param value A new value that was set on the destination object. + @param keyPath The key path in the destination object for which a new value has been set. + @param propertyMapping The `RKAttributeMapping` or `RKRelationshipMapping` found for the key path. + */ +- (void)mappingOperation:(RKMappingOperation *)operation didSetValue:(id)value forKeyPath:(NSString *)keyPath usingMapping:(RKPropertyMapping *)propertyMapping; + +/** + Tells the delegate that the mapping operation has declined to set a value for a given key path because the value has not changed. + + @param operation The object mapping operation being performed. + @param value A unchanged value for the key path in the destination object. + @param keyPath The key path in the destination object for which a unchanged value was not set. + @param propertyMapping The `RKAttributeMapping` or `RKRelationshipMapping` found for the key path. + */ +- (void)mappingOperation:(RKMappingOperation *)operation didNotSetUnchangedValue:(id)value forKeyPath:(NSString *)keyPath usingMapping:(RKPropertyMapping *)propertyMapping; + +/** + Tells the delegate that the mapping operation has failed due to an error. + + @param operation The object mapping operation that has failed. + @param error An error object indicating the reason for the failure. + */ +- (void)mappingOperation:(RKMappingOperation *)operation didFailWithError:(NSError *)error; + +///----------------------------------------- +/// @name Tracking Dynamic Mapping Selection +///----------------------------------------- + +/** + Tells the delegate that the mapping operation has selected a concrete object mapping with which to map the source object. + + Only sent if the receiver was initialized with an instance of `RKDynamicMapping` as the mapping. + + @param operation The mapping operation. + @param objectMapping The concrete object mapping with which to perform the mapping. + @param dynamicMapping The dynamic source mapping from which the object mapping was determined. + */ +- (void)mappingOperation:(RKMappingOperation *)operation didSelectObjectMapping:(RKObjectMapping *)objectMapping forDynamicMapping:(RKDynamicMapping *)dynamicMapping; + +#ifdef _COREDATADEFINES_H + +///---------------------------------------- +/// @name Tracking Relationship Connections +///---------------------------------------- + +/** + Tells the delegate that the mapping operation has connected a relationship. + + Only sent when mapping an `RKEntityMapping` object that contains connection mappings. + + @param operation The mapping operation. + @param relationship The relationship that was connected. + @param value The value that was connected to the relationship + @param connection The connection object describing how the relationship was to be connected. + */ +- (void)mappingOperation:(RKMappingOperation *)operation didConnectRelationship:(NSRelationshipDescription *)relationship toValue:(id)value usingConnection:(RKConnectionDescription *)connection; + +/** + Tells the delegate that the mapping operation failed to connect a relationship. + + Only sent when mapping an `RKEntityMapping` object that contains connection mappings. + + @param operation The mapping operation. + @param relationship The relationship that was connected. + @param connection The connection object describing how the relationship was to be connected. + */ +- (void)mappingOperation:(RKMappingOperation *)operation didFailToConnectRelationship:(NSRelationshipDescription *)relationship usingConnection:(RKConnectionDescription *)connection; + +#endif + +@end + +/** + Instances of `RKMappingOperation` perform transformation between object representations according to the rules expressed in `RKObjectMapping` objects. Mapping operations provide the foundation for the RestKit object mapping engine and perform the work of inspecting the attributes and relationships of a source object and determining how to map them into new representations on a destination object. + + ## Metadata Mapping + + The mapping operation provides support for mapping for a dictionary of metadata in addition to the source object. This metadata is made available by mapping key paths nested under a specially designated parent key that cannot exist in a source representation. By convention, metadata is typically nested under sub keys to effectively namespace usage between components. The object mapping engine itself reserves the 'mapping' key for its usage. Metadata is passed down through a hierarchy of mapping operations (i.e. as relationships are traversed), making a common set of ancillary information available for mapping for by any operation executed. + + To understand how metadata works, consider the following example: + + @interface RKMetadataExample : NSObject + @property (nonatomic, copy) NSString *name; + @property (nonatomic, copy) NSURL *URL; + @property (nonatomic, copy) NSDate *mappedAt; + @end + + RKMetadataExample *example = [RKMetadataExample new]; + NSDictionary *representation = @{ @"name": @"Blake Watters" }; + NSDictionary *metadata = @{ @"URL": [NSURL URLWithString:@"http://restkit.org"] }; + + RKObjectMapping *objectMapping = [RKObjectMapping mappingForClass:[RKMetadataExample class]]; + [objectMapping addAttributeMappingsFromDictionary:@{ @"name": @"name", @"@metadata.URL": @"URL" }]; + + RKMappingOperation *mappingOperation = [[RKMappingOperation alloc] initWithSourceObject:representation destinationObject:example mapping:objectMapping]; + mappingOperation.metadata = metadata; + + NSError *error = nil; + BOOL success = [mappingOperation execute:&error]; + + Note the use of the special key path `@"@metadata.URL"`. The `@metadata` prefix indicates that the property is to be mapped from the metadata dictionary instead of from the source object representation. If any relationships were mapped, it would have access to this same metadata information as well. + + In addition to any metadata provided to the mapping operation via the `metadata` property, the operation itself makes the following metadata key paths available for mapping: + + 1. `@metadata.mapping.collectionIndex` - An `NSNumber` object specifying the index of the current object within a collection being mapped. This key is only available if the current representation exists within a collection. + 1. `@metadata.mapping.parentObject` - The direct parent object of the object that is currently being mapped. This key is only available for objects that are mapped as relationships of a parent object. + + ## Traversing the Representation Hierarchy + + In certain mapping scenarios it can become desirable to access ancestors of the current source object. For example, consider the following example JSON: + + { + "user": { + "id": 1, + "name": "Blake Watters", + "preferences": [ + { + { + "name": "push_notifications_enabled", + "value": true, + }, + { + "name": "subscribed_to_mailing_list", + "value": false + } + } + ] + } + } + + And it's corresponding model: + + @interface RKPreferenceExample : NSObject + @property (nonatomic, strong) NSNumber *userID; + @property (nonatomic, copy) NSString *name; + @property (nonatomic, strong) id value; + @end + + Notice that `userID` is a field that we wish to model as part of our local `RKPreferenceExample` class, but its not available within the `@"preferences"` key path that our + mapping will target. In this case we'd up like to reach "up" in the parsed JSON hierarchy to access our parent node, as demonstrated in the following mapping: + + RKObjectMapping *objectMapping = [RKObjectMapping mappingForClass:[RKPreferenceExample class]]; + [objectMapping addAttributeMappingsFromDictionary:@{ @"name": @"name", @"value": @"value", @"@parent.id": @"userID" }]; + + Note the use of the `@parent` key in the final attribute mapping: this pseudo-key always points to the direct parent node of the representation being mapped (or `nil` if there is none). Parent access can be chained to traverse upward all the way to the root node of the representation. + + ### Representation Traversal Keys + + There are currently two keys provided for traversing the representation hierarchy: + + 1. `@"root"` - Returns the root node of the representation being mapped. When a large JSON document is being mapped by an instance of `RKMapperOperation` this will point to the parsed JSON document that was used to initialize the operation. + 1. `@"parent"` - Returns the direct parent node of the `sourceObject` being mapped or `nil` if the `sourceObject` is itself a root node. + */ +@interface RKMappingOperation : NSObject + +///--------------------------------------- +/// @name Initializing a Mapping Operation +///--------------------------------------- + +/** + Initializes the receiver with a source object, a destination object and an object mapping with which to perform an object mapping. + + @param sourceObject The source object to be mapped. Cannot be `nil`. + @param destinationObject The destination object the results are to be mapped onto. May be `nil`, in which case a new object target object will be obtained from the `dataSource`. + @param objectOrDynamicMapping An instance of `RKObjectMapping` or `RKDynamicMapping` defining how the mapping is to be performed. + @return The receiver, initialized with a source object, a destination object, and a mapping. + */ +- (instancetype)initWithSourceObject:(id)sourceObject destinationObject:(id)destinationObject mapping:(RKMapping *)objectOrDynamicMapping; + +/** + Initializes the receiver with a source object, a destination object and an object mapping with which to perform an object mapping, and metadata information to be made available to the mapping. + + @param sourceObject The source object to be mapped. Cannot be `nil`. + @param destinationObject The destination object the results are to be mapped onto. May be `nil`, in which case a new object target object will be obtained from the `dataSource`. + @param objectOrDynamicMapping An instance of `RKObjectMapping` or `RKDynamicMapping` defining how the mapping is to be performed. + @param metadataList A list of objects (usually dictionaries) which provide metadata to the operation, available via the @metadata key in mapping paths. Each object should respond to -valueForKeyPath:, and return nil if the requested key path is not represented in the object (in which case the following object in the list will be consulted). + @return The receiver, initialized with a source object, a destination object, and a mapping. + */ +- (instancetype)initWithSourceObject:(id)sourceObject destinationObject:(id)destinationObject mapping:(RKMapping *)objectOrDynamicMapping metadataList:(NSArray *)metadataList; + +///-------------------------------------- +/// @name Accessing Mapping Configuration +///-------------------------------------- + +/** + A dictionary of mappable elements containing simple values or nested object structures. + */ +@property (nonatomic, strong, readonly) id sourceObject; + +/** + The target object for this operation. Mappable values in the source object will be applied to the destination object using key-value coding. + + If initialized with a `nil` destination object, the mapping operation will attempt to find or create a destination object via the data source and will populate the value of the `destinationObject` property. + */ +@property (nonatomic, strong, readonly) id destinationObject; + +/** + Property which is `YES` when the destinationObject was provided from the data source, and `NO` when the destination object was provided externally to the operation. + */ +@property (nonatomic, readonly, getter=isNewDestinationObject) BOOL newDestinationObject; + +/** + The mapping defining how values contained in the source object should be transformed to the destination object via key-value coding. + + Will either be an instance of `RKObjectMapping` or `RKDynamicMapping`. + */ +@property (nonatomic, strong, readonly) RKMapping *mapping; + +/** + The concrete object mapping for the operation. + + If the value of `mapping` is an `RKObjectMapping`, returns the same value as `mapping`. If `mapping` is an `RKDynamicMapping`, then returns the concrete `RKObjectMapping` object selected for mapping `sourceObject`. + */ +@property (nonatomic, strong, readonly) RKObjectMapping *objectMapping; + +/** + A list of metadata objects available for mapping in addition to the source object. + */ +@property (nonatomic, strong, readonly) NSArray *metadataList; + +///------------------------------------------- +/// @name Configuring Delegate and Data Source +///------------------------------------------- + +/** + The delegate to inform of interesting events during the mapping operation lifecycle. + */ +@property (nonatomic, weak) id<RKMappingOperationDelegate> delegate; + +/** + The data source is responsible for providing the mapping operation with an appropriate target object for mapping when the `destinationObject` is `nil`. + + @see `RKMappingOperationDataSource` + */ +@property (nonatomic, weak) id<RKMappingOperationDataSource> dataSource; + +///-------------------------------- +/// @name Accessing Mapping Details +///-------------------------------- + +/** + The error, if any, that occurred during the execution of the mapping operation. + */ +@property (nonatomic, strong, readonly) NSError *error; + +/** + Returns a dictionary containing information about the mappings applied during the execution of the operation. The keys of the dictionary are key paths into the `destinationObject` for values that were mapped and the values are instances of `RKMappingDetails` that specify the object mapping and property mappings that were applied. + + Mapping info is aggregated for all child mapping operations executed for relationships. + */ +@property (nonatomic, readonly) RKMappingInfo *mappingInfo; + +/** + Property to indicate whether this operation has been cancelled or not. It will be `NO` until `-cancel` is called, after which it will return `YES`. + */ +@property (nonatomic, readonly, getter=isCancelled) BOOL cancelled; + +/** + Cancels the operation, by setting the `cancelled` property to `YES`. Various steps of the process check the `cancelled` property and will abort when it gets set. + */ +- (void)cancel; + +///------------------------- +/// @name Performing Mapping +///------------------------- + +/** + Process all mappable values from the mappable dictionary and assign them to the target object according to the rules expressed in the object mapping definition. The error properties need to be checked to see if the operation was successful. + */ +- (void)start; + +/** + Process all mappable values from the mappable dictionary and assign them to the target object according to the rules expressed in the object mapping definition. + + @param error A pointer to an `NSError` reference to capture any error that occurs during the mapping. May be `nil`. + @return A Boolean value indicating if the mapping operation was successful. + */ +- (BOOL)performMapping:(NSError **)error; + +@end + +/** + Specifies the concrete object mapping and collection of property mappings that were applied for a given key path during the execution of an `RKMappingOperation`. + */ +@interface RKMappingInfo : NSObject + +/** + The mapping that was applied. + */ +@property (nonatomic, strong, readonly) RKObjectMapping *objectMapping; + +/** + The dynamic mapping, if any, that was used to perform the mapping. + */ +@property (nonatomic, strong, readonly) RKDynamicMapping *dynamicMapping; + +/** + The set of property mappings that were applied from the mapping. An empty set indicates that the mapping matched the representation, but all values were unchanged and thus no properties were set. + */ +@property (nonatomic, readonly) NSSet *propertyMappings; + +/** + A dictionary whose keys are the destination key path for a mapped relationship and the value is an array of `RKMappingInfo` objects specifying the mapping details for each item within the collection. + */ +@property (nonatomic, readonly) NSDictionary *relationshipMappingInfo; + +///-------------------------------------- +/// @name Accessing Property by Subscript +///-------------------------------------- + +/** + Retrieves the property mapping with the specified destination key path. + + @param key An `NSString` object specifying the destination key path for the property that is to be retrieved. + @return The `RKPropertyMapping` with the specified destination key path or `nil` if none was found. + */ +- (id)objectForKeyedSubscript:(id)key; + +@end diff --git a/Pods/RestKit/Code/ObjectMapping/RKMappingOperation.m b/Pods/RestKit/Code/ObjectMapping/RKMappingOperation.m new file mode 100644 index 0000000..9787f17 --- /dev/null +++ b/Pods/RestKit/Code/ObjectMapping/RKMappingOperation.m @@ -0,0 +1,1261 @@ +// +// RKMappingOperation.m +// RestKit +// +// Created by Blake Watters on 4/30/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import <objc/runtime.h> +#import "RKMappingOperation.h" +#import "RKMappingErrors.h" +#import "RKPropertyInspector.h" +#import "RKAttributeMapping.h" +#import "RKRelationshipMapping.h" +#import "RKErrors.h" +#import "RKLog.h" +#import "RKMappingOperationDataSource.h" +#import "RKObjectMappingOperationDataSource.h" +#import "RKDynamicMapping.h" +#import "RKObjectUtilities.h" +#import "RKValueTransformers.h" +#import "RKDictionaryUtilities.h" + +// Set Logging Component +#undef RKLogComponent +#define RKLogComponent RKlcl_cRestKitObjectMapping + +#pragma mark - Mapping utilities + +extern NSString * const RKObjectMappingNestingAttributeKeyName; + +/** + This function ensures that attribute mappings apply cleanly to an `NSMutableDictionary` target class to support mapping to nested keyPaths. See issue #882 + */ +static void RKSetIntermediateDictionaryValuesOnObjectForKeyPath(id object, NSString *keyPath) +{ + if (! [object isKindOfClass:[NSMutableDictionary class]]) return; + NSArray *keyPathComponents = [keyPath componentsSeparatedByString:@"."]; + if ([keyPathComponents count] > 1) { + for (NSUInteger index = 0; index < [keyPathComponents count] - 1; index++) { + NSString *intermediateKeyPath = [[keyPathComponents subarrayWithRange:NSMakeRange(0, index + 1)] componentsJoinedByString:@"."]; + if (! [object valueForKeyPath:intermediateKeyPath]) { + [object setValue:[NSMutableDictionary dictionary] forKeyPath:intermediateKeyPath]; + } + } + } +} + +static BOOL RKIsManagedObject(id object) +{ + Class managedObjectClass = NSClassFromString(@"NSManagedObject"); + return managedObjectClass && [object isKindOfClass:managedObjectClass]; +} + +// Returns the appropriate value for `nil` value of a primitive type +static id RKPrimitiveValueForNilValueOfClass(Class keyValueCodingClass) +{ + if ([keyValueCodingClass isSubclassOfClass:[NSNumber class]]) { + return @0; + } else { + return nil; + } +} + +// Key comes from: nestedAttributeSubstitutionKey AND nestedAttributeSubstitutionValue; +NSArray *RKApplyNestingAttributeValueToMappings(NSString *attributeName, id value, NSArray *propertyMappings); +NSArray *RKApplyNestingAttributeValueToMappings(NSString *attributeName, id value, NSArray *propertyMappings) +{ + if (!attributeName) return propertyMappings; + + NSString *searchString = [NSString stringWithFormat:@"{%@}", attributeName]; + NSString *replacementString = [NSString stringWithFormat:@"%@", value]; + NSMutableArray *nestedMappings = [NSMutableArray arrayWithCapacity:[propertyMappings count]]; + for (RKPropertyMapping *propertyMapping in propertyMappings) { + NSString *sourceKeyPath = [propertyMapping.sourceKeyPath stringByReplacingOccurrencesOfString:searchString withString:replacementString]; + NSString *destinationKeyPath = [propertyMapping.destinationKeyPath stringByReplacingOccurrencesOfString:searchString withString:replacementString]; + RKPropertyMapping *nestedPropertyMapping = nil; + if ([propertyMapping isKindOfClass:[RKAttributeMapping class]]) { + nestedPropertyMapping = [RKAttributeMapping attributeMappingFromKeyPath:sourceKeyPath toKeyPath:destinationKeyPath]; + } else if ([propertyMapping isKindOfClass:[RKRelationshipMapping class]]) { + nestedPropertyMapping = [RKRelationshipMapping relationshipMappingFromKeyPath:sourceKeyPath + toKeyPath:destinationKeyPath + withMapping:[(RKRelationshipMapping *)propertyMapping mapping]]; + } + nestedPropertyMapping.propertyValueClass = propertyMapping.propertyValueClass; + nestedPropertyMapping.valueTransformer = propertyMapping.valueTransformer; + if (nestedPropertyMapping) [nestedMappings addObject:nestedPropertyMapping]; + } + + return nestedMappings; +} + +// Returns YES if there is a value present for at least one key path in the given collection +static BOOL RKObjectContainsValueForMappings(id representation, NSArray *propertyMappings) +{ + for (RKPropertyMapping *mapping in propertyMappings) { + NSString *keyPath = mapping.sourceKeyPath; + if (keyPath && [representation valueForKeyPath:keyPath]) return YES; + } + return NO; +} + +#pragma mark - Metadata utilities + +static NSString *const RKMetadataKey = @"@metadata"; +static NSString *const RKMetadataKeyPathPrefix = @"@metadata."; +static NSString *const RKParentKey = @"@parent"; +static NSString *const RKParentKeyPathPrefix = @"@parent."; +static NSString *const RKRootKey = @"@root"; +static NSString *const RKRootKeyPathPrefix = @"@root."; +static NSString *const RKSelfKey = @"self"; +static NSString *const RKSelfKeyPathPrefix = @"self."; + +/** + Inserts up to two objects a the start of the metadata list. metadata1 will be at the front if both are provided. + */ +static NSArray *RKInsertInMetadataList(NSArray *list, id metadata1, id metadata2) +{ + if (metadata1 == nil && metadata2 == nil) + return list; + NSMutableArray *newArray = [[NSMutableArray alloc] initWithArray:list]; + if (metadata2) + [newArray insertObject:metadata2 atIndex:0]; + if (metadata1) + [newArray insertObject:metadata1 atIndex:0]; + return newArray; +} + +@interface RKMappingSourceObject : NSObject +- (instancetype)initWithObject:(id)object parentObject:(id)parentObject rootObject:(id)rootObject metadata:(NSArray *)metadata; +- (id)metadataValueForKey:(NSString *)key; +- (id)metadataValueForKeyPath:(NSString *)keyPath; +@end + +/** + Class used in the single case of RKMappingSourceObject needing to return a single object + for the "@metadata" key, which a special implementation of -valueForKeyPath: + to iterate over the list of metadata dictionaries (which RKMappingSourceObject usually does). + This usually only happens from the parentObjectForRelationshipMapping: implementation, but + in case it does this class provides the implementation. + */ +@interface RKMetadataWrapper : NSObject +- (instancetype)initWithMappingSource:(RKMappingSourceObject *)source NS_DESIGNATED_INITIALIZER; +@property (nonatomic, strong) RKMappingSourceObject *mappingSource; +@end + +@implementation RKMetadataWrapper + +- (instancetype)initWithMappingSource:(RKMappingSourceObject *)source { + if (self = [super init]) { + self.mappingSource = source; + } + return self; +} + +- (id)valueForKey:(NSString *)key +{ + return [self.mappingSource metadataValueForKey:key]; +} +- (id)valueForKeyPath:(NSString *)keyPath +{ + return [self.mappingSource metadataValueForKeyPath:keyPath]; +} +@end + +/** + Class meant to represent parts of the "mapping" sub-dictionary of the "@metadata" keys, but + being more efficient to create than actual NSDictionary instances. We can add any object properties + to this class, and if non-nil that value will be used, otherwise it is a passthrough. + */ +@interface RKMappingMetadata : NSObject +@property (nonatomic) BOOL inValueForKeyPath; +@property (nonatomic) id parentObject; +@end + +@implementation RKMappingMetadata + +- (id)valueForKeyPath:(NSString *)keyPath +{ + static NSString *mappingPrefix = @"mapping."; + + /* We only allow paths with a "mapping." prefix, to simulate being a nested object */ + if ([keyPath hasPrefix:mappingPrefix]) { + self.inValueForKeyPath = YES; + id value = [super valueForKeyPath:[keyPath substringFromIndex:[mappingPrefix length]]]; + self.inValueForKeyPath = NO; + return value; + } + + return nil; +} + +/* Only return values from valueForKey: if we are being routed from valueForKeyPath:. This + avoids us from returning value values from say "@metadata.collectionIndex" without the mapping prefix. + */ +- (id)valueForKey:(NSString *)key +{ + return self.inValueForKeyPath? [super valueForKey:key] : nil; +} + +/* Return nil for any unknown keys, so the next object in the metadata list gets checked */ +- (id)valueForUndefinedKey:(NSString *)key +{ + return nil; +} + +@end + +/** + Subclass of RKMappingMetadata for use for holding the collectionIndex during a to-many mapping operation. + Needs to be a subclass since the scalar property cannot return nil from valueForKey, so this can only + be used when the collectionIndex is definitely set. + */ +@interface RKMappingIndexMetadata : RKMappingMetadata +@property (nonatomic) NSUInteger collectionIndex; +@end + +@implementation RKMappingIndexMetadata +@end + + +@interface RKMappingSourceObject () +@property (nonatomic, strong) id object; +@property (nonatomic, strong) id parentObject; +@property (nonatomic, strong) id rootObject; +@property (nonatomic, strong) NSArray *metadataList; +@end + +@implementation RKMappingSourceObject + +- (instancetype)initWithObject:(id)object parentObject:(id)parentObject rootObject:(id)rootObject metadata:(NSArray *)metadata +{ + self = [self init]; + if (self) { + _object = object; + _parentObject = parentObject; + _rootObject = rootObject; + _metadataList = metadata; + } + return self; +} + +- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector +{ + return [_object methodSignatureForSelector:selector]; +} + +- (void)forwardInvocation:(NSInvocation *)invocation +{ + [invocation invokeWithTarget:_object]; +} + +- (id)forwardingTargetForSelector:(SEL)aSelector +{ + return _object; +} + +- (id)metadataValueForKey:(NSString *)key +{ + for (NSDictionary *dict in self.metadataList) + { + id val = [dict valueForKey:key]; + if (val != nil) return val; + } + + return nil; +} + +- (id)metadataValueForKeyPath:(NSString *)keyPath +{ + for (NSDictionary *dict in self.metadataList) + { + id val = [dict valueForKeyPath:keyPath]; + if (val != nil) return val; + } + + return nil; +} + +- (id)valueForKey:(NSString *)key +{ + /* Using firstChar as a small performance enhancement -- one check can avoid several isEqual: calls */ + unichar firstChar = [key length] > 0 ? [key characterAtIndex:0] : 0; + + if (firstChar == 's' && [key isEqualToString:RKSelfKey]) { + return _object; + } else if (firstChar != '@') { + return [_object valueForKey:key]; + } else if ([key isEqualToString:RKMetadataKey]) { + return [[RKMetadataWrapper alloc] initWithMappingSource:self]; + } else if ([key isEqualToString:RKParentKey]) { + return self.parentObject; + } else if ([key isEqualToString:RKRootKey]) { + return self.rootObject; + } else { + return [_object valueForKey:key]; + } +} + +/** + NOTE: We implement `valueForKeyPath:` on the proxy instead of using `forwardInvocation:` because the OS X runtime fails to appropriately handle scalar boxing/unboxing, resulting in incorrect metadata mappings. Proxying the method directly produces the expected results on both OS X and iOS [sbw - 2/1/2012] + */ +- (id)valueForKeyPath:(NSString *)keyPath +{ + /* Using firstChar as a small performance enhancement -- one check can avoid several hasPrefix calls */ + unichar firstChar = [keyPath length] > 0 ? [keyPath characterAtIndex:0] : 0; + + if (firstChar == 's' && [keyPath hasPrefix:RKSelfKeyPathPrefix]) { + NSString *selfKeyPath = [keyPath substringFromIndex:[RKSelfKeyPathPrefix length]]; + return [_object valueForKeyPath:selfKeyPath]; + } else if (firstChar != '@') { + return [_object valueForKeyPath:keyPath]; + } else if ([keyPath hasPrefix:RKMetadataKeyPathPrefix]) { + NSString *metadataKeyPath = [keyPath substringFromIndex:[RKMetadataKeyPathPrefix length]]; + return [self metadataValueForKeyPath:metadataKeyPath]; + } else if ([keyPath hasPrefix:RKParentKeyPathPrefix]) { + NSString *parentKeyPath = [keyPath substringFromIndex:[RKParentKeyPathPrefix length]]; + return [self.parentObject valueForKeyPath:parentKeyPath]; + } else if ([keyPath hasPrefix:RKRootKeyPathPrefix]) { + NSString *rootKeyPath = [keyPath substringFromIndex:[RKRootKeyPathPrefix length]]; + return [self.rootObject valueForKeyPath:rootKeyPath]; + } else { + return [_object valueForKeyPath:keyPath]; + } +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@"%@ (%@)", [self.object description], self.metadataList]; +} + +- (Class)class +{ + return [_object class]; +} + +- (BOOL)isKindOfClass:(Class)aClass +{ + return [_object isKindOfClass:aClass]; +} + +- (BOOL)respondsToSelector:(SEL)aSelector +{ + return [_object respondsToSelector:aSelector]; +} + +- (BOOL)conformsToProtocol:(Protocol *)aProtocol +{ + return [_object conformsToProtocol:aProtocol]; +} + +- (Class)rk_classForPropertyAtKeyPath:(NSString *)keyPath isPrimitive:(BOOL *)isPrimitive +{ + return [_object rk_classForPropertyAtKeyPath:keyPath isPrimitive:isPrimitive]; +} + +@end + + +#pragma mark - RKMappingInfo + +@interface RKMappingInfo () +@property (nonatomic, assign, readwrite) NSUInteger collectionIndex; +@property (nonatomic, strong) NSMutableSet *mutablePropertyMappings; +@property (nonatomic, strong) NSMutableDictionary *mutableRelationshipMappingInfo; + +- (instancetype)initWithObjectMapping:(RKObjectMapping *)objectMapping dynamicMapping:(RKDynamicMapping *)dynamicMapping; +- (void)addPropertyMapping:(RKPropertyMapping *)propertyMapping; +@end + +@implementation RKMappingInfo + +- (instancetype)initWithObjectMapping:(RKObjectMapping *)objectMapping dynamicMapping:(RKDynamicMapping *)dynamicMapping +{ + self = [self init]; + if (self) { + _objectMapping = objectMapping; + _dynamicMapping = dynamicMapping; + _mutablePropertyMappings = [NSMutableSet setWithCapacity:[objectMapping.propertyMappings count]]; + _mutableRelationshipMappingInfo = [NSMutableDictionary dictionaryWithCapacity:[objectMapping.relationshipMappings count]]; + } + return self; +} + +- (NSSet *)propertyMappings +{ + return [self.mutablePropertyMappings copy]; +} + +- (NSDictionary *)relationshipMappingInfo +{ + return [self.mutableRelationshipMappingInfo copy]; +} + +- (void)addPropertyMapping:(RKPropertyMapping *)propertyMapping +{ + [self.mutablePropertyMappings addObject:propertyMapping]; +} + +- (void)addMappingInfo:(RKMappingInfo *)mappingInfo forRelationshipMapping:(RKRelationshipMapping *)relationshipMapping +{ + NSMutableArray *arrayOfMappingInfo = (self.mutableRelationshipMappingInfo)[relationshipMapping.destinationKeyPath]; + if (arrayOfMappingInfo) { + [arrayOfMappingInfo addObject:mappingInfo]; + } else { + arrayOfMappingInfo = [NSMutableArray arrayWithObject:mappingInfo]; + (self.mutableRelationshipMappingInfo)[relationshipMapping.destinationKeyPath] = arrayOfMappingInfo; + } +} + +- (id)objectForKeyedSubscript:(id)key +{ + for (RKPropertyMapping *propertyMapping in self.mutablePropertyMappings) { + if ([propertyMapping.destinationKeyPath isEqualToString:key]) { + return propertyMapping; + } + } + return nil; +} + +@end + +#pragma mark - RKMappingOperation + +@interface RKMappingOperation () +@property (nonatomic, strong, readwrite) RKMapping *mapping; +@property (nonatomic, strong, readwrite) id sourceObject; +@property (nonatomic, strong, readwrite) id parentSourceObject; +@property (nonatomic, strong, readwrite) id rootSourceObject; +@property (nonatomic, strong, readwrite) id destinationObject; +@property (nonatomic, strong, readwrite) NSArray *metadataList; +@property (nonatomic, strong) NSString *nestedAttributeSubstitutionKey; +@property (nonatomic, strong) id nestedAttributeSubstitutionValue; +@property (nonatomic, strong, readwrite) NSError *error; +@property (nonatomic, strong, readwrite) RKObjectMapping *objectMapping; // The concrete mapping +@property (nonatomic, strong) NSArray *nestedAttributeMappings; +@property (nonatomic, strong) NSArray *simpleAttributeMappings; +@property (nonatomic, strong) NSArray *keyPathAttributeMappings; +@property (nonatomic, strong) NSArray *relationshipMappings; +@property (nonatomic, strong) RKMappingInfo *mappingInfo; +@property (nonatomic, getter=isCancelled) BOOL cancelled; +@property (nonatomic) BOOL collectsMappingInfo; +@property (nonatomic) BOOL shouldSetUnchangedValues; +@property (nonatomic, readwrite, getter=isNewDestinationObject) BOOL newDestinationObject; +@end + +@implementation RKMappingOperation + +- (instancetype)initWithSourceObject:(id)sourceObject destinationObject:(id)destinationObject mapping:(RKMapping *)objectOrDynamicMapping +{ + return [self initWithSourceObject:sourceObject destinationObject:destinationObject mapping:objectOrDynamicMapping metadataList:nil]; +} + +- (instancetype)initWithSourceObject:(id)sourceObject destinationObject:(id)destinationObject mapping:(RKMapping *)objectOrDynamicMapping metadataList:(NSArray *)metadataList +{ + NSAssert(sourceObject != nil, @"Cannot perform a mapping operation without a sourceObject object"); + NSAssert(objectOrDynamicMapping != nil, @"Cannot perform a mapping operation without a mapping"); + + self = [super init]; + if (self) { + self.sourceObject = sourceObject; + self.rootSourceObject = sourceObject; + self.destinationObject = destinationObject; + self.mapping = objectOrDynamicMapping; + self.metadataList = metadataList; + } + + return self; +} + +- (id)parentObjectForRelationshipMapping:(RKRelationshipMapping *)mapping +{ + id parentSourceObject = self.sourceObject; + NSString *sourceKeyPath = mapping.sourceKeyPath; + + NSRange lastDotRange = [sourceKeyPath rangeOfString:@"." options:NSBackwardsSearch|NSLiteralSearch]; + if (lastDotRange.length > 0) + { + NSString *parentKey = [sourceKeyPath substringToIndex:lastDotRange.location]; + id rootObject = self.rootSourceObject; + NSArray *metadata = self.metadataList; + for (NSString *key in [parentKey componentsSeparatedByString:@"."]) + { + parentSourceObject = [[RKMappingSourceObject alloc] initWithObject:[parentSourceObject valueForKey:key] + parentObject:parentSourceObject + rootObject:rootObject + metadata:metadata]; + } + } + + return parentSourceObject; +} + +- (id)destinationObjectForMappingRepresentation:(id)representation parentRepresentation:(id)parentRepresentation withMapping:(RKMapping *)mapping inRelationship:(RKRelationshipMapping *)relationshipMapping +{ + RKObjectMapping *concreteMapping = nil; + if ([mapping isKindOfClass:[RKDynamicMapping class]]) { + concreteMapping = [(RKDynamicMapping *)mapping objectMappingForRepresentation:representation]; + if (! concreteMapping) { + RKLogDebug(@"Unable to determine concrete object mapping from dynamic mapping %@ with which to map object representation: %@", mapping, representation); + return nil; + } + } else if ([mapping isKindOfClass:[RKObjectMapping class]]) { + concreteMapping = (RKObjectMapping *)mapping; + } + + id destinationObject = nil; + id dataSource = self.dataSource; + if ([dataSource respondsToSelector:@selector(mappingOperation:targetObjectForMapping:inRelationship:)]) + { + destinationObject = [dataSource mappingOperation:self targetObjectForMapping:concreteMapping inRelationship:relationshipMapping]; + } + + if (destinationObject == nil) + { + NSDictionary *dictionaryRepresentation = [representation isKindOfClass:[NSDictionary class]] ? representation : @{ [NSNull null] : representation }; + RKMappingMetadata *parentMetadata = [RKMappingMetadata new]; + parentMetadata.parentObject = self.destinationObject ?: [NSNull null]; + NSArray *metadata = RKInsertInMetadataList(self.metadataList, parentMetadata, nil); + RKMappingSourceObject *sourceObject = [[RKMappingSourceObject alloc] initWithObject:dictionaryRepresentation parentObject:parentRepresentation rootObject:self.rootSourceObject metadata:metadata]; + destinationObject = [dataSource mappingOperation:self targetObjectForRepresentation:(NSDictionary *)sourceObject withMapping:concreteMapping inRelationship:relationshipMapping]; + } + + return destinationObject; +} + +- (BOOL)validateValue:(id *)value atKeyPath:(NSString *)keyPath +{ + BOOL success = YES; + + if (self.objectMapping.performsKeyValueValidation) { + id destinationObject = self.destinationObject; + + if ([destinationObject respondsToSelector:@selector(validateValue:forKeyPath:error:)]) { + NSError *validationError; + success = [destinationObject validateValue:value forKeyPath:keyPath error:&validationError]; + if (!success) { + self.error = validationError; + if (validationError) { + RKLogError(@"Validation failed while mapping attribute at key path '%@' to value. Error: %@", keyPath, [validationError localizedDescription]); + RKLogValidationError(validationError); + } else { + RKLogWarning(@"Destination object %@ rejected attribute value for keyPath %@. Skipping...", self.destinationObject, keyPath); + } + RKLogDebug(@"(Value for key path '%@': %@)", keyPath, *value); + } + } + } + + return success; +} + +- (BOOL)shouldSetValue:(id *)value forKeyPath:(NSString *)keyPath usingMapping:(RKPropertyMapping *)propertyMapping +{ + if ([self.delegate respondsToSelector:@selector(mappingOperation:shouldSetValue:forKeyPath:usingMapping:)]) { + return [self.delegate mappingOperation:self shouldSetValue:*value forKeyPath:keyPath usingMapping:propertyMapping]; + } + + // Always set the properties + if (self.shouldSetUnchangedValues) { + return [self validateValue:value atKeyPath:keyPath]; + } + + id currentValue = [self.destinationObject valueForKeyPath:keyPath]; + if (currentValue == [NSNull null]) { + currentValue = nil; + } + + /* + WTF - This workaround should not be necessary, but I have been unable to replicate + the circumstances that trigger it in a unit test to fix elsewhere. The proper place + to handle it is in transformValue:atKeyPath:toType: + + See issue & pull request: https://github.com/RestKit/RestKit/pull/436 + */ + if (*value == [NSNull null]) *value = nil; + + if (nil == currentValue && nil == *value) { + // Both are nil + return NO; + } else if (nil == *value || nil == currentValue) { + // One is nil and the other is not + return [self validateValue:value atKeyPath:keyPath]; + } + + if (! RKObjectIsEqualToObject(*value, currentValue)) { + // Validate value for key + return [self validateValue:value atKeyPath:keyPath]; + } + return NO; +} + +- (NSArray *)applyNestingToMappings:(NSArray *)propertyMappings +{ + if (self.nestedAttributeSubstitutionKey == nil) return propertyMappings; + + return RKApplyNestingAttributeValueToMappings(self.nestedAttributeSubstitutionKey, self.nestedAttributeSubstitutionValue, propertyMappings); +} + +- (void)cacheMappingsIfNeeded +{ + if (!_nestedAttributeMappings) + { + RKObjectMapping *mapping = self.objectMapping; + + if (self.nestedAttributeSubstitutionKey == nil) { + _relationshipMappings = mapping.relationshipMappings; + _nestedAttributeMappings = mapping.attributeMappings; + _simpleAttributeMappings = mapping.keyAttributeMappings; + _keyPathAttributeMappings = mapping.keyPathAttributeMappings; + } + else { + _nestedAttributeMappings = [self applyNestingToMappings:mapping.attributeMappings]; + _relationshipMappings = [self applyNestingToMappings:mapping.relationshipMappings]; + NSMutableArray *simpleList = [[NSMutableArray alloc] initWithCapacity:[_nestedAttributeMappings count]]; + NSMutableArray *keyPathList = [[NSMutableArray alloc] initWithCapacity:[_nestedAttributeMappings count]]; + + // The nested substitution may have changed which properties are simple vs keyPath, so we have to + // re-check based on the nesting result. + for (RKPropertyMapping *mapping in _nestedAttributeMappings) { + BOOL isSimple = [mapping.sourceKeyPath rangeOfString:@"." options:NSLiteralSearch].length == 0; + NSMutableArray *arrayToAdd = isSimple? simpleList : keyPathList; + [arrayToAdd addObject:mapping]; + } + + _simpleAttributeMappings = simpleList; + _keyPathAttributeMappings = keyPathList; + } + } +} + +- (NSArray *)nestedAttributeMappings +{ + [self cacheMappingsIfNeeded]; + return _nestedAttributeMappings; +} + +- (NSArray *)simpleAttributeMappings +{ + [self cacheMappingsIfNeeded]; + return _simpleAttributeMappings; +} + +- (NSArray *)keyPathAttributeMappings +{ + [self cacheMappingsIfNeeded]; + return _keyPathAttributeMappings; +} + +- (NSArray *)relationshipMappings +{ + [self cacheMappingsIfNeeded]; + return _relationshipMappings; +} + +- (BOOL)transformValue:(id)inputValue toValue:(__autoreleasing id *)outputValue withPropertyMapping:(RKPropertyMapping *)propertyMapping error:(NSError *__autoreleasing *)error +{ + if (! inputValue) { + *outputValue = nil; + // We only want to consider the transformation successful and assign nil if the mapping calls for it + return propertyMapping.objectMapping.assignsDefaultValueForMissingAttributes; + } + Class transformedValueClass = propertyMapping.propertyValueClass ?: [self.objectMapping classForKeyPath:propertyMapping.destinationKeyPath]; + if (! transformedValueClass) { + *outputValue = inputValue; + return YES; + } + RKLogTrace(@"Found transformable value at keyPath '%@'. Transforming from class '%@' to '%@'", propertyMapping.sourceKeyPath, NSStringFromClass([inputValue class]), NSStringFromClass(transformedValueClass)); + BOOL success = [propertyMapping.valueTransformer transformValue:inputValue toValue:outputValue ofClass:transformedValueClass error:error]; + if (! success) RKLogError(@"Failed transformation of value at keyPath '%@' to representation of type '%@': %@", propertyMapping.sourceKeyPath, transformedValueClass, *error); + return success; +} + +- (BOOL)applyAttributeMapping:(RKAttributeMapping *)attributeMapping withValue:(id)value +{ + id transformedValue = nil; + NSError *error = nil; + if (! [self transformValue:value toValue:&transformedValue withPropertyMapping:attributeMapping error:&error]) return NO; + + NSString *destinationKeyPath = attributeMapping.destinationKeyPath; + id destinationObject = self.destinationObject; + id delegate = self.delegate; + + if ([delegate respondsToSelector:@selector(mappingOperation:didFindValue:forKeyPath:mapping:)]) { + [delegate mappingOperation:self didFindValue:value forKeyPath:attributeMapping.sourceKeyPath mapping:attributeMapping]; + } + RKLogTrace(@"Mapping attribute value keyPath '%@' to '%@'", attributeMapping.sourceKeyPath, destinationKeyPath); + + // If we have a nil value for a primitive property, we need to coerce it into a KVC usable value or bail out + if (transformedValue == nil && RKPropertyInspectorIsPropertyAtKeyPathOfObjectPrimitive(destinationKeyPath, destinationObject)) { + RKLogDebug(@"Detected `nil` value transformation for primitive property at keyPath '%@'", destinationKeyPath); + transformedValue = RKPrimitiveValueForNilValueOfClass([self.objectMapping classForKeyPath:destinationKeyPath]); + if (! transformedValue) { + RKLogTrace(@"Skipped mapping of attribute value from keyPath '%@ to keyPath '%@' -- Unable to transform `nil` into primitive value representation", attributeMapping.sourceKeyPath, destinationKeyPath); + return NO; + } + } + + RKSetIntermediateDictionaryValuesOnObjectForKeyPath(destinationObject, destinationKeyPath); + + // Ensure that the value is different + if ([self shouldSetValue:&transformedValue forKeyPath:destinationKeyPath usingMapping:attributeMapping]) { + RKLogTrace(@"Mapped attribute value from keyPath '%@' to '%@'. Value: %@", attributeMapping.sourceKeyPath, destinationKeyPath, transformedValue); + + if (destinationKeyPath) { + [destinationObject setValue:transformedValue forKeyPath:destinationKeyPath]; + } else { + if ([destinationObject isKindOfClass:[NSMutableDictionary class]] && [transformedValue isKindOfClass:[NSDictionary class]]) { + [destinationObject setDictionary:transformedValue]; + } else { + [NSException raise:NSInvalidArgumentException format:@"Unable to set value for destination object of type '%@': Can only directly set destination object for `NSMutableDictionary` targets. (transformedValue=%@)", [destinationObject class], transformedValue]; + } + } + if ([delegate respondsToSelector:@selector(mappingOperation:didSetValue:forKeyPath:usingMapping:)]) { + [delegate mappingOperation:self didSetValue:transformedValue forKeyPath:destinationKeyPath usingMapping:attributeMapping]; + } + } else { + RKLogTrace(@"Skipped mapping of attribute value from keyPath '%@ to keyPath '%@' -- value is unchanged (%@)", attributeMapping.sourceKeyPath, destinationKeyPath, transformedValue); + if ([delegate respondsToSelector:@selector(mappingOperation:didNotSetUnchangedValue:forKeyPath:usingMapping:)]) { + [delegate mappingOperation:self didNotSetUnchangedValue:transformedValue forKeyPath:destinationKeyPath usingMapping:attributeMapping]; + } + } + if (_collectsMappingInfo) { + [self.mappingInfo addPropertyMapping:attributeMapping]; + } + return YES; +} + +// Return YES if we mapped any attributes +- (BOOL)applyAttributeMappings:(NSArray *)attributeMappings +{ + // If we have a nesting substitution value, we have already succeeded + BOOL appliedMappings = (self.nestedAttributeSubstitutionKey != nil); + + if (!self.objectMapping.performsKeyValueValidation) { + RKLogDebug(@"Key-value validation is disabled for mapping, skipping..."); + } + + id sourceObject = self.sourceObject; + + for (RKAttributeMapping *attributeMapping in attributeMappings) { + if ([self isCancelled]) return NO; + + NSString *sourceKeyPath = attributeMapping.sourceKeyPath; + NSString *destinationKeyPath = attributeMapping.destinationKeyPath; + if ([sourceKeyPath isEqualToString:RKObjectMappingNestingAttributeKeyName] || [destinationKeyPath isEqualToString:RKObjectMappingNestingAttributeKeyName]) { + RKLogTrace(@"Skipping attribute mapping for special keyPath '%@'", sourceKeyPath); + continue; + } + + id value = (sourceKeyPath == nil) ? [sourceObject valueForKey:@"self"] : [sourceObject valueForKeyPath:sourceKeyPath]; + if ([self applyAttributeMapping:attributeMapping withValue:value]) { + appliedMappings = YES; + } else { + id delegate = self.delegate; + RKObjectMapping *objectMapping = self.objectMapping; + + if ([delegate respondsToSelector:@selector(mappingOperation:didNotFindValueForKeyPath:mapping:)]) { + [delegate mappingOperation:self didNotFindValueForKeyPath:sourceKeyPath mapping:attributeMapping]; + } + RKLogTrace(@"Did not find mappable attribute value keyPath '%@'", sourceKeyPath); + + // Optionally set the default value for missing values + if (objectMapping.assignsDefaultValueForMissingAttributes) { + [self.destinationObject setValue:[objectMapping defaultValueForAttribute:destinationKeyPath] + forKeyPath:destinationKeyPath]; + RKLogTrace(@"Setting nil for missing attribute value at keyPath '%@'", sourceKeyPath); + } + } + + // Fail out if an error has occurred + if (self.error) break; + } + + return appliedMappings; +} + +- (BOOL)mapNestedObject:(id)anObject toObject:(id)anotherObject parent:(id)parentSourceObject withRelationshipMapping:(RKRelationshipMapping *)relationshipMapping metadataList:(NSArray *)metadataList +{ + NSAssert(anObject, @"Cannot map nested object without a nested source object"); + NSAssert(anotherObject, @"Cannot map nested object without a destination object"); + NSAssert(relationshipMapping, @"Cannot map a nested object relationship without a relationship mapping"); + + RKLogTrace(@"Performing nested object mapping using mapping %@ for data: %@", relationshipMapping, anObject); + RKMappingOperation *subOperation = [[RKMappingOperation alloc] initWithSourceObject:anObject destinationObject:anotherObject mapping:relationshipMapping.mapping metadataList:metadataList]; + subOperation.dataSource = self.dataSource; + subOperation.delegate = self.delegate; + subOperation.parentSourceObject = parentSourceObject; + subOperation.rootSourceObject = self.rootSourceObject; + subOperation.newDestinationObject = YES; + [subOperation start]; + + if (subOperation.error) { + RKLogWarning(@"WARNING: Failed mapping nested object: %@", [subOperation.error localizedDescription]); + } else if (self.collectsMappingInfo) { + RKMappingInfo *mappingInfo = self.mappingInfo; + RKMappingInfo *subMappingInfo = subOperation.mappingInfo; + [mappingInfo addPropertyMapping:relationshipMapping]; + if (subMappingInfo) { + [mappingInfo addMappingInfo:subMappingInfo forRelationshipMapping:relationshipMapping]; + } + } + + return YES; +} + +- (BOOL)applyReplaceAssignmentPolicyForRelationshipMapping:(RKRelationshipMapping *)relationshipMapping +{ + if (relationshipMapping.assignmentPolicy == RKReplaceAssignmentPolicy) { + id dataSource = self.dataSource; + if ([dataSource respondsToSelector:@selector(mappingOperation:deleteExistingValueOfRelationshipWithMapping:error:)]) { + NSError *error = nil; + BOOL success = [dataSource mappingOperation:self deleteExistingValueOfRelationshipWithMapping:relationshipMapping error:&error]; + if (! success) { + RKLogError(@"Failed to delete existing value of relationship mapped with RKReplaceAssignmentPolicy: %@", error); + self.error = error; + return NO; + } + } else { + RKLogWarning(@"Requested mapping with `RKReplaceAssignmentPolicy` assignment policy, but the data source does not support it. Mapping has proceeded identically to the `RKSetAssignmentPolicy`."); + } + } + + return YES; +} + +- (BOOL)mapOneToOneRelationshipWithValue:(id)value mapping:(RKRelationshipMapping *)relationshipMapping +{ + static dispatch_once_t onceToken; + static NSDictionary *noIndexMetadata; + dispatch_once(&onceToken, ^{ + noIndexMetadata = @{ @"mapping" : @{ @"collectionIndex" : [NSNull null] } }; + }); + + // One to one relationship + NSString *destinationKeyPath = relationshipMapping.destinationKeyPath; + RKLogDebug(@"Mapping one to one relationship value at keyPath '%@' to '%@'", relationshipMapping.sourceKeyPath, destinationKeyPath); + + if (relationshipMapping.assignmentPolicy == RKUnionAssignmentPolicy) { + NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: @"Invalid assignment policy: cannot union a one-to-one relationship." }; + self.error = [NSError errorWithDomain:RKErrorDomain code:RKMappingErrorInvalidAssignmentPolicy userInfo:userInfo]; + return NO; + } + + // Remove existing destination entity before mapping the new one + if (relationshipMapping.assignmentPolicy == RKAssignmentPolicyReplace && ![self applyReplaceAssignmentPolicyForRelationshipMapping:relationshipMapping]) { + return NO; + } + + id parentSourceObject = [self parentObjectForRelationshipMapping:relationshipMapping]; + id destinationObject = [self destinationObjectForMappingRepresentation:value parentRepresentation:parentSourceObject withMapping:relationshipMapping.mapping inRelationship:relationshipMapping]; + if (! destinationObject) { + RKLogDebug(@"Mapping %@ declined mapping for representation %@: returned `nil` destination object.", relationshipMapping.mapping, destinationObject); + return NO; + } + + NSArray *subOperationMetadata = RKInsertInMetadataList(self.metadataList, noIndexMetadata, nil); + [self mapNestedObject:value toObject:destinationObject parent:parentSourceObject withRelationshipMapping:relationshipMapping metadataList:subOperationMetadata]; + + // If the relationship has changed, set it + if ([self shouldSetValue:&destinationObject forKeyPath:destinationKeyPath usingMapping:relationshipMapping]) { + RKLogTrace(@"Mapped relationship object from keyPath '%@' to '%@'. Value: %@", relationshipMapping.sourceKeyPath, destinationKeyPath, destinationObject); + [self.destinationObject setValue:destinationObject forKeyPath:destinationKeyPath]; + } else { + if ([self.delegate respondsToSelector:@selector(mappingOperation:didNotSetUnchangedValue:forKeyPath:usingMapping:)]) { + [self.delegate mappingOperation:self didNotSetUnchangedValue:destinationObject forKeyPath:destinationKeyPath usingMapping:relationshipMapping]; + } + } + + return YES; +} + +- (BOOL)mapCoreDataToManyRelationshipValue:(id)valueForRelationship withMapping:(RKRelationshipMapping *)relationshipMapping +{ + id destinationObject = self.destinationObject; + if (! RKIsManagedObject(destinationObject)) return NO; + + RKLogTrace(@"Mapping a to-many relationship for an `NSManagedObject`. About to apply value via mutable[Set|Array]ValueForKey"); + if ([valueForRelationship isKindOfClass:[NSSet class]]) { + RKLogTrace(@"Mapped `NSSet` relationship object from keyPath '%@' to '%@'. Value: %@", relationshipMapping.sourceKeyPath, relationshipMapping.destinationKeyPath, valueForRelationship); + NSMutableSet *destinationSet = [destinationObject mutableSetValueForKeyPath:relationshipMapping.destinationKeyPath]; + [destinationSet setSet:valueForRelationship]; + } else if ([valueForRelationship isKindOfClass:[NSArray class]]) { + RKLogTrace(@"Mapped `NSArray` relationship object from keyPath '%@' to '%@'. Value: %@", relationshipMapping.sourceKeyPath, relationshipMapping.destinationKeyPath, valueForRelationship); + NSMutableArray *destinationArray = [destinationObject mutableArrayValueForKeyPath:relationshipMapping.destinationKeyPath]; + [destinationArray setArray:valueForRelationship]; + } else if ([valueForRelationship isKindOfClass:[NSOrderedSet class]]) { + RKLogTrace(@"Mapped `NSOrderedSet` relationship object from keyPath '%@' to '%@'. Value: %@", relationshipMapping.sourceKeyPath, relationshipMapping.destinationKeyPath, valueForRelationship); + [destinationObject setValue:valueForRelationship forKeyPath:relationshipMapping.destinationKeyPath]; + } + + return YES; +} + +- (BOOL)mapOneToManyRelationshipWithValue:(id)value mapping:(RKRelationshipMapping *)relationshipMapping +{ + NSString *destinationKeyPath = relationshipMapping.destinationKeyPath; + + // One to many relationship + RKLogDebug(@"Mapping one to many relationship value at keyPath '%@' to '%@'", relationshipMapping.sourceKeyPath, destinationKeyPath); + + NSMutableArray *relationshipCollection = [NSMutableArray arrayWithCapacity:[value count]]; + if (RKObjectIsCollectionOfCollections(value)) { + RKLogWarning(@"WARNING: Detected a relationship mapping for a collection containing another collection. This is probably not what you want. Consider using a KVC collection operator (such as @unionOfArrays) to flatten your mappable collection."); + RKLogWarning(@"Key path '%@' yielded collection containing another collection rather than a collection of objects", relationshipMapping.sourceKeyPath); + RKLogDebug(@"(Value at key path '%@': %@)", relationshipMapping.sourceKeyPath, value); + } + + if (relationshipMapping.assignmentPolicy == RKUnionAssignmentPolicy) { + RKLogDebug(@"Mapping relationship with union assignment policy: constructing combined relationship value."); + id existingObjects = [self.destinationObject valueForKeyPath:destinationKeyPath]; + if (existingObjects) { + NSArray *existingObjectsArray = nil; + NSError *error = nil; + [[RKValueTransformer defaultValueTransformer] transformValue:existingObjects toValue:&existingObjectsArray ofClass:[NSArray class] error:&error]; + [relationshipCollection addObjectsFromArray:existingObjectsArray]; + } + } + else if (relationshipMapping.assignmentPolicy == RKReplaceAssignmentPolicy) { + if (! [self applyReplaceAssignmentPolicyForRelationshipMapping:relationshipMapping]) { + return NO; + } + } + + RKMapping *relationshipDestinationMapping = relationshipMapping.mapping; + id parentSourceObject = [self parentObjectForRelationshipMapping:relationshipMapping]; + RKMappingIndexMetadata *indexMetadata = [RKMappingIndexMetadata new]; + NSArray *subOperationMetadata = RKInsertInMetadataList(self.metadataList, indexMetadata, nil); + [value enumerateObjectsUsingBlock:^(id nestedObject, NSUInteger collectionIndex, BOOL *stop) { + id mappableObject = [self destinationObjectForMappingRepresentation:nestedObject parentRepresentation:parentSourceObject withMapping:relationshipDestinationMapping inRelationship:relationshipMapping]; + if (mappableObject) { + indexMetadata.collectionIndex = collectionIndex; + if ([self mapNestedObject:nestedObject toObject:mappableObject parent:parentSourceObject withRelationshipMapping:relationshipMapping metadataList:subOperationMetadata]) { + [relationshipCollection addObject:mappableObject]; + } + } else { + RKLogDebug(@"Mapping %@ declined mapping for representation %@: returned `nil` destination object.", relationshipDestinationMapping, nestedObject); + } + }]; + + id valueForRelationship = nil; + NSError *error = nil; + if (! [self transformValue:relationshipCollection toValue:&valueForRelationship withPropertyMapping:relationshipMapping error:&error]) return NO; + + // If the relationship has changed, set it + if ([self shouldSetValue:&valueForRelationship forKeyPath:destinationKeyPath usingMapping:relationshipMapping]) { + if (! [self mapCoreDataToManyRelationshipValue:valueForRelationship withMapping:relationshipMapping]) { + RKLogTrace(@"Mapped relationship object from keyPath '%@' to '%@'. Value: %@", relationshipMapping.sourceKeyPath, destinationKeyPath, valueForRelationship); + [self.destinationObject setValue:valueForRelationship forKeyPath:destinationKeyPath]; + } + } else { + if ([self.delegate respondsToSelector:@selector(mappingOperation:didNotSetUnchangedValue:forKeyPath:usingMapping:)]) { + [self.delegate mappingOperation:self didNotSetUnchangedValue:valueForRelationship forKeyPath:destinationKeyPath usingMapping:relationshipMapping]; + } + + return NO; + } + + return YES; +} + +- (BOOL)applyRelationshipMappings +{ + NSAssert(self.dataSource, @"Cannot perform relationship mapping without a data source"); + NSUInteger mappingsApplied = 0; + RKObjectMapping *parentObjectMapping = self.objectMapping; + id sourceObject = self.sourceObject; + id destinationObject = self.destinationObject; + id delegate = self.delegate; + + for (RKRelationshipMapping *relationshipMapping in [self relationshipMappings]) { + if ([self isCancelled]) return NO; + + NSString *sourceKeyPath = relationshipMapping.sourceKeyPath; + NSString *destinationKeyPath = relationshipMapping.destinationKeyPath; + id value = nil; + + if (sourceKeyPath) { + value = [sourceObject valueForKeyPath:sourceKeyPath]; + } else { + // The nil source keyPath indicates that we want to map directly from the parent representation + value = sourceObject; + RKMapping *destinationMapping = relationshipMapping.mapping; + RKObjectMapping *objectMapping = nil; + + if ([destinationMapping isKindOfClass:[RKObjectMapping class]]) { + objectMapping = (RKObjectMapping *)destinationMapping; + } else if ([destinationMapping isKindOfClass:[RKDynamicMapping class]]) { + objectMapping = [(RKDynamicMapping *)destinationMapping objectMappingForRepresentation:value]; + } + + if (! objectMapping) continue; // Mapping declined + if (! RKObjectContainsValueForMappings(value, objectMapping.propertyMappings)) { + continue; + } + } + + // Track that we applied this mapping + mappingsApplied++; + + if (value == nil) { + RKLogDebug(@"Did not find mappable relationship value keyPath '%@'", sourceKeyPath); + if (! parentObjectMapping.assignsNilForMissingRelationships) continue; + } + + if (value == [NSNull null]) { + RKLogDebug(@"Found null value at keyPath '%@'", sourceKeyPath); + value = nil; + } + + // nil out the property if necessary + if (value == nil) { + Class relationshipClass = [parentObjectMapping classForKeyPath:destinationKeyPath]; + BOOL mappingToCollection = RKClassIsCollection(relationshipClass); + RKAssignmentPolicy assignmentPolicy = relationshipMapping.assignmentPolicy; + if (assignmentPolicy == RKUnionAssignmentPolicy && mappingToCollection) { + // Unioning `nil` with the existing value is functionally equivalent to doing nothing, so just continue + continue; + } else if (assignmentPolicy == RKUnionAssignmentPolicy) { + NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: @"Invalid assignment policy: cannot union a one-to-one relationship." }; + self.error = [NSError errorWithDomain:RKErrorDomain code:RKMappingErrorInvalidAssignmentPolicy userInfo:userInfo]; + continue; + } else if (assignmentPolicy == RKReplaceAssignmentPolicy) { + if (! [self applyReplaceAssignmentPolicyForRelationshipMapping:relationshipMapping]) { + continue; + } + } + + if ([self shouldSetValue:&value forKeyPath:destinationKeyPath usingMapping:relationshipMapping]) { + RKLogTrace(@"Setting nil for relationship value at keyPath '%@'", sourceKeyPath); + [destinationObject setValue:value forKeyPath:destinationKeyPath]; + } + + continue; + } + + // Handle case where incoming content is collection represented by a dictionary + if (relationshipMapping.mapping.forceCollectionMapping) { + // If we have forced mapping of a dictionary, map each subdictionary + if ([value isKindOfClass:[NSDictionary class]]) { + RKLogDebug(@"Collection mapping forced for NSDictionary, mapping each key/value independently..."); + NSArray *objectsToMap = [NSMutableArray arrayWithCapacity:[value count]]; + for (id key in value) { + NSDictionary *dictionaryToMap = @{key: [value valueForKey:key]}; + [(NSMutableArray *)objectsToMap addObject:dictionaryToMap]; + } + value = objectsToMap; + } else { + RKLogWarning(@"Collection mapping forced but mappable objects is of type '%@' rather than NSDictionary", NSStringFromClass([value class])); + } + } + + // Handle case where incoming content is a single object, but we want a collection + Class relationshipClass = [parentObjectMapping classForKeyPath:destinationKeyPath]; + BOOL mappingToCollection = RKClassIsCollection(relationshipClass); + BOOL objectIsCollection = RKObjectIsCollection(value); + if (mappingToCollection && !objectIsCollection) { + RKLogDebug(@"Asked to map a single object into a collection relationship. Transforming to an instance of: %@", NSStringFromClass(relationshipClass)); + if ([relationshipClass isSubclassOfClass:[NSArray class]]) { + value = [relationshipClass arrayWithObject:value]; + objectIsCollection = YES; + } else if ([relationshipClass isSubclassOfClass:[NSSet class]]) { + value = [relationshipClass setWithObject:value]; + objectIsCollection = YES; + } else if ([relationshipClass isSubclassOfClass:[NSOrderedSet class]]) { + value = [relationshipClass orderedSetWithObject:value]; + objectIsCollection = YES; + } else { + RKLogWarning(@"Failed to transform single object"); + } + } + + BOOL setValueForRelationship; + if (objectIsCollection) { + setValueForRelationship = [self mapOneToManyRelationshipWithValue:value mapping:relationshipMapping]; + } else { + setValueForRelationship = [self mapOneToOneRelationshipWithValue:value mapping:relationshipMapping]; + } + + if (! setValueForRelationship) continue; + + // Notify the delegate + if ([delegate respondsToSelector:@selector(mappingOperation:didSetValue:forKeyPath:usingMapping:)]) { + id setValue = [destinationObject valueForKeyPath:destinationKeyPath]; + [delegate mappingOperation:self didSetValue:setValue forKeyPath:destinationKeyPath usingMapping:relationshipMapping]; + } + + // Fail out if a validation error has occurred + if (self.error) break; + } + + return mappingsApplied > 0; +} + +- (void)applyNestedMappings +{ + RKObjectMapping *objectMapping = self.objectMapping; + RKAttributeMapping *attributeMapping = [objectMapping mappingForSourceKeyPath:RKObjectMappingNestingAttributeKeyName]; + if (attributeMapping) { + RKLogDebug(@"Found nested mapping definition to attribute '%@'", attributeMapping.destinationKeyPath); + id attributeValue = [[self.sourceObject allKeys] lastObject]; + if (attributeValue) { + RKLogDebug(@"Found nesting value of '%@' for attribute '%@'", attributeValue, attributeMapping.destinationKeyPath); + self.nestedAttributeSubstitutionKey = attributeMapping.destinationKeyPath; + self.nestedAttributeSubstitutionValue = attributeValue; + [self applyAttributeMapping:attributeMapping withValue:attributeValue]; + } else { + RKLogWarning(@"Unable to find nesting value for attribute '%@'", attributeMapping.destinationKeyPath); + } + } + + // Serialization + attributeMapping = [objectMapping mappingForDestinationKeyPath:RKObjectMappingNestingAttributeKeyName]; + if (attributeMapping) { + RKLogDebug(@"Found nested mapping definition to attribute '%@'", attributeMapping.destinationKeyPath); + id attributeValue = [self.sourceObject valueForKeyPath:attributeMapping.sourceKeyPath]; + if (attributeValue) { + RKLogDebug(@"Found nesting value of '%@' for attribute '%@'", attributeValue, attributeMapping.sourceKeyPath); + self.nestedAttributeSubstitutionKey = attributeMapping.sourceKeyPath; + self.nestedAttributeSubstitutionValue = attributeValue; + } else { + RKLogWarning(@"Unable to find nesting value for attribute '%@'", attributeMapping.destinationKeyPath); + } + } +} + +- (void)cancel +{ + self.cancelled = YES; + RKLogDebug(@"Mapping operation cancelled: %@", self); +} + +- (void)start +{ + [self main]; +} + +- (void)main +{ + if ([self isCancelled]) return; + + // Handle metadata + id parentSourceObject = self.parentSourceObject; + id sourceObject = [[RKMappingSourceObject alloc] initWithObject:self.sourceObject parentObject:parentSourceObject rootObject:self.rootSourceObject metadata:self.metadataList]; + self.sourceObject = sourceObject; + + RKLogDebug(@"Starting mapping operation..."); + RKLogTrace(@"Performing mapping operation: %@", self); + + id dataSource = self.dataSource; + id delegate = self.delegate; + RKMapping *mapping = self.mapping; + RKObjectMapping *objectMapping; + + if (! self.destinationObject) { + self.destinationObject = [self destinationObjectForMappingRepresentation:sourceObject parentRepresentation:parentSourceObject withMapping:mapping inRelationship:nil]; + if (! self.destinationObject) { + RKLogDebug(@"Mapping operation failed: Given nil destination object and unable to instantiate a destination object for mapping."); + NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: @"Cannot perform a mapping operation with a nil destination object." }; + self.error = [NSError errorWithDomain:RKErrorDomain code:RKMappingErrorNilDestinationObject userInfo:userInfo]; + return; + } + self.newDestinationObject = YES; + } + + self.collectsMappingInfo = (![dataSource respondsToSelector:@selector(mappingOperationShouldCollectMappingInfo:)] || + [dataSource mappingOperationShouldCollectMappingInfo:self]); + + self.shouldSetUnchangedValues = ([self.dataSource respondsToSelector:@selector(mappingOperationShouldSetUnchangedValues:)] && + [self.dataSource mappingOperationShouldSetUnchangedValues:self]); + + // Determine the concrete mapping if we were initialized with a dynamic mapping + if ([mapping isKindOfClass:[RKDynamicMapping class]]) { + self.objectMapping = objectMapping = [(RKDynamicMapping *)mapping objectMappingForRepresentation:sourceObject]; + if (! objectMapping) { + NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: @"A dynamic mapping failed to return a concrete object mapping matching the representation being mapped." }; + self.error = [NSError errorWithDomain:RKErrorDomain code:RKMappingErrorUnableToDetermineMapping userInfo:userInfo]; + return; + } + RKLogDebug(@"RKObjectMappingOperation was initialized with a dynamic mapping. Determined concrete mapping = %@", objectMapping); + + if ([delegate respondsToSelector:@selector(mappingOperation:didSelectObjectMapping:forDynamicMapping:)]) { + [delegate mappingOperation:self didSelectObjectMapping:objectMapping forDynamicMapping:(RKDynamicMapping *)mapping]; + } + if (self.collectsMappingInfo) { + self.mappingInfo = [[RKMappingInfo alloc] initWithObjectMapping:objectMapping dynamicMapping:(RKDynamicMapping *)mapping]; + } + } else if ([mapping isKindOfClass:[RKObjectMapping class]]) { + self.objectMapping = objectMapping = (RKObjectMapping *)mapping; + if (self.collectsMappingInfo) { + self.mappingInfo = [[RKMappingInfo alloc] initWithObjectMapping:objectMapping dynamicMapping:nil]; + } + } + + BOOL canSkipMapping = [dataSource respondsToSelector:@selector(mappingOperationShouldSkipPropertyMapping:)] && [dataSource mappingOperationShouldSkipPropertyMapping:self]; + if (! canSkipMapping) { + [self applyNestedMappings]; + if ([self isCancelled]) return; + BOOL mappedSimpleAttributes = [self applyAttributeMappings:[self simpleAttributeMappings]]; + if ([self isCancelled]) return; + BOOL mappedRelationships = [[self relationshipMappings] count] ? [self applyRelationshipMappings] : NO; + if ([self isCancelled]) return; + // NOTE: We map key path attributes last to allow you to map across the object graphs for objects created/updated by the relationship mappings + BOOL mappedKeyPathAttributes = [self applyAttributeMappings:[self keyPathAttributeMappings]]; + + if (!mappedSimpleAttributes && !mappedRelationships && !mappedKeyPathAttributes) { + // We did not find anything to do + RKLogDebug(@"Mapping operation did not find any mappable values for the attribute and relationship mappings in the given object representation"); + NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: @"No mappable values found for any of the attributes or relationship mappings" }; + self.error = [NSError errorWithDomain:RKErrorDomain code:RKMappingErrorUnmappableRepresentation userInfo:userInfo]; + } + + // We did some mapping work, if there's no error let's commit our changes to the data source + if (self.error == nil) { + if ([dataSource respondsToSelector:@selector(commitChangesForMappingOperation:error:)]) { + NSError *error = nil; + BOOL success = [dataSource commitChangesForMappingOperation:self error:&error]; + if (! success) { + self.error = error; + } + } + } + } + + if (self.error) { + if ([delegate respondsToSelector:@selector(mappingOperation:didFailWithError:)]) { + [delegate mappingOperation:self didFailWithError:self.error]; + } + + RKLogDebug(@"Failed mapping operation: %@", [self.error localizedDescription]); + } else { + RKLogDebug(@"Finished mapping operation successfully..."); + } +} + +- (BOOL)performMapping:(NSError **)error +{ + [self start]; + if (error) *error = self.error; + return self.error == nil; +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@"<%@ %p> for '%@' object. Mapping values from object %@ to object %@ with object mapping %@", + [self class], self, NSStringFromClass([self.destinationObject class]), self.sourceObject, self.destinationObject, self.objectMapping]; +} + +@end diff --git a/Pods/RestKit/Code/ObjectMapping/RKMappingOperationDataSource.h b/Pods/RestKit/Code/ObjectMapping/RKMappingOperationDataSource.h new file mode 100644 index 0000000..2d06b34 --- /dev/null +++ b/Pods/RestKit/Code/ObjectMapping/RKMappingOperationDataSource.h @@ -0,0 +1,110 @@ +// +// RKMappingOperationDataSource.h +// RestKit +// +// Created by Blake Watters on 7/3/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import <Foundation/Foundation.h> + +@class RKObjectMapping, RKMappingOperation, RKRelationshipMapping; + +/** + An object that adopts the `RKMappingOperationDataSource` protocol is responsible for the retrieval or creation of target objects within an `RKMapperOperation` or `RKMappingOperation`. A data source is responsible for meeting the requirements of the underlying data store implementation and must return a key-value coding compliant object instance that can be used as the target object of a mapping operation. It is also responsible for commiting any changes necessary to the underlying data store once a mapping operation has completed its work. + + At a minimum, a data source must implement the `mappingOperation:targetObjectForRepresentation:withMapping:` method. This method is responsible for finding an existing object instance to be updated or creating a new object if no existing object could be found or the underlying data store does not support persistence. Object mapping operations which target `NSObject` derived classes will always result in mapping to new transient objects, while persistent data stores such as Core Data can be queried to retrieve existing objects for update. + + @see `RKManagedObjectMappingOperationDataSource` + */ +@protocol RKMappingOperationDataSource <NSObject> + +@required + +/** + Asks the data source for the target object for an object mapping operation given an `NSDictionary` representation of the object's properties and the mapping object that will be used to perform the mapping. + + The `representation` value is a fragment of content from a deserialized response that has been identified as containing content that is mappable using the given mapping. + + @param mappingOperation The mapping operation requesting the target object. + @param representation A dictionary representation of the properties to be mapped onto the retrieved target object. + @param mapping The object mapping to be used to perform a mapping from the representation to the target object. + @return A key-value coding compliant object to perform the mapping on to. + */ +- (id)mappingOperation:(RKMappingOperation *)mappingOperation targetObjectForRepresentation:(NSDictionary *)representation withMapping:(RKObjectMapping *)mapping inRelationship:(RKRelationshipMapping *)relationshipMapping; + +@optional + +/** + Asks the data source for the target object for an object mapping operation the mapping object that will be used to perform the mapping. + + If not implemented or it returns nil, then the + `mappingOperation:targetObjectForRepresentation:withMapping:inRelationship:` method will be called to determine the target. + + It is preferable to implement this method if the `representation` is not needed to determine the target object, + as obtaining that value is somewhat expensive. + + @param mappingOperation The mapping operation requesting the target object. + @param representation A dictionary representation of the properties to be mapped onto the retrieved target object. + @param mapping The object mapping to be used to perform a mapping from the representation to the target object. + @return A key-value coding compliant object to perform the mapping on to. + */ +- (id)mappingOperation:(RKMappingOperation *)mappingOperation targetObjectForMapping:(RKObjectMapping *)mapping inRelationship:(RKRelationshipMapping *)relationshipMapping; + + +/** + Tells the data source to commit any changes to the underlying data store. + + @param mappingOperation The mapping operation that has completed its work. + @param error A pointer to an error to be set in the event that the mapping operation could not be committed. + @return A Boolean value indicating if the changes for the mapping operation were committed successfully. + */ +- (BOOL)commitChangesForMappingOperation:(RKMappingOperation *)mappingOperation error:(NSError **)error; + +/** + Tells the data source to delete the existing value for a relationship that has been mapped with an assignment policy of `RKReplaceAssignmentPolicy`. + + @param mappingOperation The mapping operation that is executing. + @param relationshipMapping The relationship mapping for which the existing value is being replaced. + @param error A pointer to an error to be set in the event that the deletion operation could not be completed. + @return A Boolean value indicating if the existing objects for the relationship were successfully deleted. + */ +- (BOOL)mappingOperation:(RKMappingOperation *)mappingOperation deleteExistingValueOfRelationshipWithMapping:(RKRelationshipMapping *)relationshipMapping error:(NSError **)error; + +/** + Asks the data source if it should set values for properties without checking that the value has been changed. This method can result in a performance improvement during mapping as the mapping operation will not attempt to assess the change state of the property being mapped. + + If this method is not implemented by the data source, then the mapping operation defaults to `NO`. + + @param mappingOperation The mapping operation that is querying the data source. + @return `YES` if the mapping operation should disregard property change status, else `NO`. + */ +- (BOOL)mappingOperationShouldSetUnchangedValues:(RKMappingOperation *)mappingOperation; + +- (BOOL)mappingOperationShouldSkipPropertyMapping:(RKMappingOperation *)mappingOperation; + +/** + Asks the data source if the mapping operation should collect `RKMappingInfo` information during the mapping + (stored in the `mappingInfo` property). If not needed, it can be a substantially faster to skip it. The + `mappingInfo` property will be nil if not collected. + + If this method is not implemented by the data source, then the mapping operation defaults to `YES`. + + @param mappingOperation The mapping operation that is querying the data source. + @return `YES` if the mapping operation should collect mapping information, else `NO`. +*/ +- (BOOL)mappingOperationShouldCollectMappingInfo:(RKMappingOperation *)mappingOperation; + +@end diff --git a/Pods/RestKit/Code/ObjectMapping/RKMappingResult.h b/Pods/RestKit/Code/ObjectMapping/RKMappingResult.h new file mode 100644 index 0000000..2cdeff0 --- /dev/null +++ b/Pods/RestKit/Code/ObjectMapping/RKMappingResult.h @@ -0,0 +1,91 @@ +// +// RKMappingResult.h +// RestKit +// +// Created by Blake Watters on 5/7/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import <Foundation/Foundation.h> + +/** + The `RKMappingResult` class represents the aggregate object mapping results returned by an `RKMapperOperation` object. The mapping result provides a thin interface on top of an `NSDictionary` and provides convenient interfaces for accessing the mapping results in various representations. + */ +@interface RKMappingResult : NSObject + +///---------------------------------------- +/// @name Creating a Mapping Result +///---------------------------------------- + +/** + Initializes the receiver with a dictionary of mapped key paths and object values. + + @param dictionary A dictionary wherein the keys represent mapped key paths and the values represent the objects mapped at those key paths. Cannot be nil. + @return The receiver, initialized with the given dictionary. + */ +- (instancetype)initWithDictionary:(NSDictionary *)dictionary; + +///---------------------------------------- +/// @name Retrieving Result Representations +///---------------------------------------- + +/** + Returns a representation of the mapping result as a dictionary. + + The keys of the returned dictionary will correspond to the mapped key paths in the source object representation and the values will be the mapped objects. The returned value is a copy of the dictionary that was used to initialize the mapping result. + + @return A dictionary containing the mapping results. + */ +- (NSDictionary *)dictionary; + +/** + Returns a representation of the mapping result as a single object by returning the first mapped value from the aggregate array of mapped objects. + + The mapping result is coerced into a single object by retrieving all mapped objects and returning the first object. If the mapping result is empty, `nil` is returned. + + @return The first object contained in the mapping result. + */ +@property (nonatomic, readonly, strong) id firstObject; + +/** + Returns a representation of the mapping result as an array of objects. + + The array returned is a flattened collection of all mapped object values contained in the underlying dictionary result representation. No guarantee is made as to the ordering of objects within the returned collection when more than one key path was mapped, as `NSDictionary` objects are unordered, + + @return An array containing the objects contained in the mapping result. + */ +- (NSArray *)array; + +/** + Returns a representation of the mapping result as a set of objects. + + The set returned is a flattened collection of all mapped object values contained in the underlying dictionary result representation. + + @return A set containing the objects contained in the mapping result. + */ +@property (nonatomic, readonly, copy) NSSet *set; + +///---------------------------------------- +/// @name Counting Entries +///---------------------------------------- + +/** + Returns a count of the number of objects contained in the mapping result. This is an aggregate count of all objects across all mapped key paths in the result. + + @return A count of the number of mapped objects in the mapping result. + */ +@property (nonatomic, readonly) NSUInteger count; + +@end diff --git a/Pods/RestKit/Code/ObjectMapping/RKMappingResult.m b/Pods/RestKit/Code/ObjectMapping/RKMappingResult.m new file mode 100644 index 0000000..d3b7f58 --- /dev/null +++ b/Pods/RestKit/Code/ObjectMapping/RKMappingResult.m @@ -0,0 +1,81 @@ +// +// RKMappingResult.m +// RestKit +// +// Created by Blake Watters on 5/7/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKMappingResult.h" + +@interface RKMappingResult () +@property (nonatomic, strong) NSDictionary *keyPathToMappedObjects; +@end + +@implementation RKMappingResult + +- (instancetype)initWithDictionary:(id)dictionary +{ + NSParameterAssert(dictionary); + self = [self init]; + if (self) { + self.keyPathToMappedObjects = dictionary; + } + + return self; +} + +- (NSDictionary *)dictionary +{ + return [self.keyPathToMappedObjects copy]; +} + +- (NSArray *)array +{ + // Flatten results down into a single array + NSMutableArray *collection = [NSMutableArray array]; + for (id object in [self.keyPathToMappedObjects allValues]) { + // We don't want to strip the keys off of a mapped dictionary result + if (NO == [object isKindOfClass:[NSDictionary class]] && [object respondsToSelector:@selector(allObjects)]) { + [collection addObjectsFromArray:[object allObjects]]; + } else { + [collection addObject:object]; + } + } + + return collection; +} + +- (NSSet *)set +{ + return [NSSet setWithArray:[self array]]; +} + +- (id)firstObject +{ + return [[self array] firstObject]; +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@"<%@: %p, results=%@>", NSStringFromClass([self class]), self, self.keyPathToMappedObjects]; +} + +- (NSUInteger)count +{ + return [[self array] count]; +} + +@end diff --git a/Pods/RestKit/Code/ObjectMapping/RKObjectMapping.h b/Pods/RestKit/Code/ObjectMapping/RKObjectMapping.h new file mode 100644 index 0000000..ff15c62 --- /dev/null +++ b/Pods/RestKit/Code/ObjectMapping/RKObjectMapping.h @@ -0,0 +1,529 @@ +// +// RKObjectMapping.h +// RestKit +// +// Created by Blake Watters on 4/30/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKMacros.h" +#import "RKMapping.h" + +#import <RKValueTransformers/RKValueTransformers.h> + +@class RKPropertyMapping, RKAttributeMapping, RKRelationshipMapping; +@protocol RKValueTransforming; + +/** + An `RKObjectMapping` object describes a transformation between object represenations using key-value coding and run-time type introspection. The mapping is defined in terms of a source object class and a collection of `RKPropertyMapping` objects describing how key paths in the source representation should be transformed into attributes and relationships on the target object. Object mappings are provided to instances of `RKMapperOperation` and `RKMappingOperation` to perform the transformations they describe. + + Object mappings are containers of property mappings that describe the actual key path transformations. There are two types of property mappings: + + 1. `RKAttributeMapping`: An attribute mapping describes a transformation between a single value from a source key path to a destination key path. The value to be mapped is read from the source object representation using `valueForKeyPath:` and then set to the destination key path using `setValueForKeyPath:`. Before the value is set, the `RKObjecMappingOperation` performing the mapping performs runtime introspection on the destination property to determine what, if any, type transformation is to be performed. Typical type transformations include reading an `NSString` value representation and mapping it to an `NSDecimalNumber` destination key path or reading an `NSString` and transforming it into an `NSDate` value before assigning to the destination. + 1. `RKRelationshipMapping`: A relationship mapping describes a transformation between a nested child object or objects from a source key path to a destination key path using another `RKObjectMapping`. The child objects to be mapped are read from the source object representation using `valueForKeyPath:`, then mapped recursively using the object mapping associated with the relationship mapping, and then finally assigned to the destination key path. Before assignment to the destination key path runtime type introspection is performed to determine if any type transformation is necessary. For relationship mappings, common type transformations include transforming a single object value in an `NSArray` or transforming an `NSArray` of object values into an `NSSet`. + + All type transformations available are discussed in detail in the documentation for `RKValueTransformer`. + + ## Transforming Representation to Property Keys + + Configuring object mappings can become quite repetitive if the keys in your serialized object representations follow a different convention than their local domain counterparts. For example, consider a typical JSON document in the "snake case" format: + + {"user": {"first_name": "Blake", "last_name": "Watters", "email_address": "blake@restkit.org"}} + + Typically when configuring a mapping for the object represented in this document we would transform the destination properties into the Objective-C idiomatic "llama case" variation. This can produce lengthy, error-prone mapping configurations in which the transformations are specified manually: + + RKObjectMapping *userMapping = [RKObjectMapping mappingForClass:[RKUser class]]; + [userMapping addAttributeMappingsFromDictionary:@{ @"first_name": @"firstName", @"last_name": @"lastName", @"email_address", @"emailAddress" }]; + + To combat this repetition, a block can be designated to perform a transformation on source keys to produce corresponding destination keys: + + [userMapping setSourceToDestinationKeyTransformationBlock:^NSString *(RKObjectMapping *mapping, NSString *sourceKey) { + // Value transformer compliments of TransformerKit (See https://github.com/mattt/TransformerKit) + return [[NSValueTransformer valueTransformerForName:TKLlamaCaseStringTransformerName] transformedValue:sourceKey]; + }]; + + With the block configured, the original configuration can be changed into a simpler array based invocation: + + [userMapping addAttributeMappingsFromArray:@[ @"first_name", @"last_name", @"email_address" ]]; + + Transformation blocks can be configured on a per-mapping basis via `setSourceToDestinationKeyTransformationBlock:` or globally via `[RKObjectMapping setDefaultSourceToDestinationKeyTransformationBlock:]`. + + @see `RKAttributeMapping` + @see `RKRelationshipMapping` + @see `RKConnectionMapping` + @see `RKMappingOperation` + @see `RKPropertyInspector` + */ +@interface RKObjectMapping : RKMapping <NSCopying> + +///--------------------------------- +/// @name Creating an Object Mapping +///--------------------------------- + +/** + Returns an object mapping for the specified class that is ready for configuration + + @param objectClass The class that the mapping targets. + @return A new mapping object. + */ ++ (instancetype)mappingForClass:(Class)objectClass; + +/** + Initializes the receiver with a given object class. This is the designated initializer. + + @param objectClass The class that the mapping targets. Cannot be `nil`. + @return The receiver, initialized with the given class. + */ +- (instancetype)initWithClass:(Class)objectClass; + +/** + Returns an object mapping with an `objectClass` of `NSMutableDictionary`. + + Request mappings are used when configuring mappings that are to be used for transforming local objects into HTTP parameters using the `RKObjectParameterization` class. + + @return An object mapping with an object class of `NSMutableDictionary`. + @see `RKObjectParameterization` + @see `RKObjectManager` + */ ++ (RKObjectMapping *)requestMapping; + +///---------------------------------- +/// @name Accessing Property Mappings +///---------------------------------- + +/** + The aggregate collection of attribute and relationship mappings within this object mapping. + */ +@property (nonatomic, copy, readonly) NSArray *propertyMappings; + +/** + Returns the property mappings of the receiver in a dictionary, where the keys are the source key paths and the values are instances of `RKAttributeMapping` or `RKRelationshipMapping`. + + @return The property mappings of the receiver in a dictionary, where the keys are the source key paths and the values are instances of `RKAttributeMapping` or `RKRelationshipMapping`. + @warning Note this method does not return any property mappings with a `nil` value for the source key path in the dictionary returned. + */ +@property (nonatomic, readonly) NSDictionary *propertyMappingsBySourceKeyPath; + +/** + Returns the property mappings of the receiver in a dictionary, where the keys are the destination key paths and the values are instances of `RKAttributeMapping` or `RKRelationshipMapping`. + + @return The property mappings of the receiver in a dictionary, where the keys are the destination key paths and the values are instances of `RKAttributeMapping` or `RKRelationshipMapping`. + @warning Note this method does not return any property mappings with a `nil` value for the source key path in the dictionary returned. + */ +@property (nonatomic, readonly) NSDictionary *propertyMappingsByDestinationKeyPath; + +/** + The collection of attribute mappings within this object mapping. + */ +@property (nonatomic, readonly) NSArray *attributeMappings; + +/** + The collection of single key attribute mappings within this object mapping. + + These are mappings where the source key path is a single key, and not a key path with multiple components. + */ +@property (nonatomic, readonly) NSArray *keyAttributeMappings; + +/** + The collection of key path attribute mappings within this object mapping. + + A key path mapping is one where the source key path is actually a path with multiple components. + */ +@property (nonatomic, readonly) NSArray *keyPathAttributeMappings; + +/** + The collection of relationship mappings within this object mapping. + */ +@property (nonatomic, readonly) NSArray *relationshipMappings; + +/** + Returns the property mapping registered with the receiver with the given source key path. + + @param sourceKeyPath The key path to retrieve. + */ +- (id)mappingForSourceKeyPath:(NSString *)sourceKeyPath; + +/** + Returns the property mapping registered with the receiver with the given destinationKeyPath key path. + + @param destinationKeyPath The key path to retrieve. + */ +- (id)mappingForDestinationKeyPath:(NSString *)destinationKeyPath; + +///--------------------------- +/// Managing Property Mappings +///--------------------------- + +/** + Adds a property mapping to the receiver. + + @param propertyMapping The property mapping to be added to the object mapping. + */ +- (void)addPropertyMapping:(RKPropertyMapping *)propertyMapping; + +/** + Adds an array of `RKAttributeMapping` or `RKRelationshipMapping` objects to the receiver. + + @param arrayOfPropertyMappings The array of property mappings to be added to the object mapping. + */ +- (void)addPropertyMappingsFromArray:(NSArray *)arrayOfPropertyMappings; + +/** + Removes an `RKAttributeMapping` or `RKRelationshipMapping` from the receiver. + + @param propertyMapping The attribute or relationship mapping to remove. + */ +- (void)removePropertyMapping:(RKPropertyMapping *)propertyMapping; + +/** + Adds attribute mappings from a given dictionary wherein the keys represent the source key path and the values represent the names of the target attributes on the destination object. + + @param keyPathToAttributeNames A dictionary keyed by source key to destination attribute name. + */ +- (void)addAttributeMappingsFromDictionary:(NSDictionary *)keyPathToAttributeNames; + +/** + Adds attribute mappings to the receiver from a given array. + + The array can contain `RKAttributeMapping` objects or `NSString` values. If an `NSString` is given, then a new `RKAttributeMapping` object is instantiated with a `sourceKeyPath` and `destinationKeyPath` equal to the string value. + + @param arrayOfAttributeNamesOrMappings An array of `RKAttributeMapping` or `NSString` values to be added to the receiver's set of attribute mappings, + */ +- (void)addAttributeMappingsFromArray:(NSArray *)arrayOfAttributeNamesOrMappings; + +/** + Adds a relationship mapping to the receiver with the given source key path and mapping. + + The destination key path will be the same as the source key path or processed by the source to destination key transformation block, if any is configured. + + @param sourceKeyPath The source key path at which to read the nested representation of the related objects. + @param mapping The object mapping with which to process the related object representation. + */ +- (void)addRelationshipMappingWithSourceKeyPath:(NSString *)sourceKeyPath mapping:(RKMapping *)mapping; + +///------------------------------------- +/// @name Configuring Key Transformation +///------------------------------------- + +/** + Sets an application-wide default transformation block to be used when attribute or relationship mappings are added to an object mapping by source key path. + + @param block The block to be set as the default source to destination key transformer for all object mappings in the application. + @see [RKObjectMapping setPropertyNameTransformationBlock:] + */ ++ (void)setDefaultSourceToDestinationKeyTransformationBlock:(NSString * (^)(RKObjectMapping *mapping, NSString *sourceKey))block; + +/** + Sets a block to executed to transform a source key into a destination key. + + The transformation block set with this method is used whenever an attribute or relationship mapping is added to the receiver via a method that accepts a string value for the source key. The block will be executed with the source key as the only argument and the value returned will be taken as the corresponding destination key. Methods on the `RKObjectMapping` class that will trigger the execution of the block configured via this method include: + * `addAttributeMappingsFromArray:` - Each string element contained in the given array is interpretted as a source key path and will be evaluated with the block to obtain a corresponding destination key path. + * `addRelationshipMappingWithSourceKeyPath:mapping:` - The source key path will be evaluated with the block to obtain a corresponding destination key path. + + @param block The block to execute when the receiver needs to transform a source key into a destination key. The block has a string return value specifying the destination key and accepts a single string argument: the source key that is to be transformed. + @warning Please note that the block given accepts a **key** as opposed to a **key path**. When a key path is given to a method supporting key transformation it will be decomposed into its key components by splitting the key path at the '.' (period) character, then each key will be evaluated using the transformation block and the results will be joined together into a new key path with the period character delimiter. + */ +- (void)setSourceToDestinationKeyTransformationBlock:(NSString * (^)(RKObjectMapping *mapping, NSString *sourceKey))block; + +///---------------------------------- +/// @name Mapping Nested Dictionaries +///---------------------------------- + +/** + Adds an attribute mapping from a dynamic nesting key value to an attribute. The mapped attribute name can then be referenced within other attribute mappings to access the nested content. + + For example, consider the following JSON: + + { "users": + { + "blake": { "id": 1234, "email": "blake@restkit.org" }, + "rachit": { "id": 5678, "email": "rachit@restkit.org" } + } + } + + We can configure our mappings to handle this in the following form: + + RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[User class]]; + mapping.forceCollectionMapping = YES; // RestKit cannot infer this is a collection, so we force it + [mapping addAttributeMappingFromKeyOfRepresentationToAttribute:@"firstName"]; + [mapping addAttributeMappingsFromDictionary:@{ @"{firstName}.id": @"userID", @"{firstName}.email": @"email" }]; + */ +- (void)addAttributeMappingFromKeyOfRepresentationToAttribute:(NSString *)attributeName; + +/** + Adds an attribute mapping to a dynamic nesting key from an attribute. The mapped attribute name can then be referenced wthin other attribute mappings to map content under the nesting key path. + + For example, consider that we wish to map a local user object with the properties 'id', 'firstName' and 'email': + + RKUser *user = [RKUser new]; + user.firstName = @"blake"; + user.userID = @(1234); + user.email = @"blake@restkit.org"; + + And we wish to map it into JSON that looks like: + + { "blake": { "id": 1234, "email": "blake@restkit.org" } } + + We can configure our request mapping to handle this like so: + + RKObjectMapping *mapping = [RKObjectMapping requestMapping]; + [mapping addAttributeMappingToKeyOfRepresentationFromAttribute:@"firstName"]; + [mapping addAttributeMappingsFromDictionary:@{ @"userID": @"{firstName}.id", @"email": @"{firstName}.email" }]; + */ +- (void)addAttributeMappingToKeyOfRepresentationFromAttribute:(NSString *)attributeName; + +///---------------------------------- +/// @name Configuring Mapping Options +///---------------------------------- + +/** + The target class that the receiver describes a mapping for. + */ +@property (nonatomic, weak, readonly) Class objectClass; + +/** + When `YES`, any attributes that have mappings defined but are not present within the source object will be set to nil, clearing any existing value. + + **Default**: `NO` + */ +@property (nonatomic, assign) BOOL assignsDefaultValueForMissingAttributes; + +/** + When `YES`, any relationships that have mappings defined but are not present within the source object will be set to `nil`, clearing any existing value. + + **Default**: `NO` + */ +@property (nonatomic, assign) BOOL assignsNilForMissingRelationships; + +/** + When `YES`, key-value validation will be invoked at object mapping time. + + **Default**: `YES` + @see `validateValue:forKey:error:` + */ +@property (nonatomic, assign) BOOL performsKeyValueValidation; + +/** + A value transformer with which to process input values being mapped with the receiver. Defaults to a copy of `[RKValueTransformer defaultTransformer]`. + */ +@property (nonatomic, strong) id<RKValueTransforming> valueTransformer; + +/** + Returns the default value to be assigned to the specified attribute when it is missing from a mappable payload. + + The default implementation returns nil for transient object mappings. On an entity mapping, the default value returned from the Entity definition will be used. + + @see `[RKEntityMapping defaultValueForAttribute:]` + */ +- (id)defaultValueForAttribute:(NSString *)attributeName; + +///---------------------------------- +/// @name Generating Inverse Mappings +///---------------------------------- + +/** + Generates an inverse mapping for the rules specified within this object mapping. + + This can be used to quickly generate a corresponding serialization mapping from a configured object mapping. The inverse mapping will have the source and destination keyPaths swapped for all attribute and relationship mappings. All mapping configuration and date formatters are copied from the parent to the inverse mapping. + + @return A new mapping that will map the inverse of the receiver. + */ +- (instancetype)inverseMapping; + +/** + Generates an inverse mapping with all property mappings of the receiver that pass the given test. Each `RKAttributeMapping` and `RKRelationshipMapping` added to the receiver is yielded to the block for evaluation. The block is also invoked for any nested relationships that are traversed during the inversion process. + + @param predicate A block object to be invoked for each `RKPropertyMapping` that is considered for inversion. The block has a Boolean return value and accepts a single argument: the property mapping that is being evaluated for inversion. + @return A new mapping that will map the inverse of the receiver. + @see inverseMapping + */ +- (instancetype)inverseMappingWithPropertyMappingsPassingTest:(BOOL (^)(RKPropertyMapping *propertyMapping))predicate; + +///--------------------------------------------------- +/// @name Obtaining Information About the Target Class +///--------------------------------------------------- + +/** + Returns the class of the attribute or relationship property of the target `objectClass` with the given name. + + Given the name of a string property, this will return an `NSString`, etc. + + @param propertyName The name of the property we would like to retrieve the type of. + @return The class of the property. + */ +- (Class)classForProperty:(NSString *)propertyName; + +/** + Returns the class of the attribute or relationship property of the target `objectClass` at the given key path. + + Given a key path to a string property, this will return an `NSString`, etc. + + @param keyPath The name of the property we would like to retrieve the type of. + @return The class of the property at the given key path. + */ +- (Class)classForKeyPath:(NSString *)keyPath; + +@end + +///////////////////////////////////////////////////////////////////////////// + +/** + **Deprecated in v0.21.0** + + This category contains deprecated API interfaces for configuring date formatters. Starting in RestKit 0.20.4 date formatting is configured via the `RKValueTransformer` API's. + + Defines the interface for configuring time and date formatting handling within RestKit object mappings. For performance reasons, RestKit reuses a pool of date formatters rather than constructing them at mapping time. This collection of date formatters can be configured on a per-object mapping or application-wide basis using the static methods exposed in this category. + */ +@interface RKObjectMapping (LegacyDateAndTimeFormatting) + +/** + **Deprecated in v0.21.0** + + This method accesses `[RKValueTransformer defaultTransformer]` and returns all `NSDate` <-> `NSString` value transformers. + + Returns the collection of default date formatters that will be used for all object mappings that have not been configured specifically. + + Out of the box, RestKit initializes default date formatters for you in the UTC time zone with the following format strings: + + * `yyyy-MM-dd'T'HH:mm:ss'Z'` + * `MM/dd/yyyy` + + @return An array of `NSFormatter` objects used when mapping strings into NSDate attributes + */ ++ (NSArray *)defaultDateFormatters DEPRECATED_ATTRIBUTE_MESSAGE("Configure `[RKValueTransformer defaultValueTransformer]` instead"); + +/** + **Deprecated in v0.21.0** + + This method accesses `[RKValueTransformer defaultTransformer]` and removes all `NSDate` <-> `NSString` value transformers that are instances of `NSFormatter` and then adds the given array of formatters to the default transformer. + + Sets the collection of default date formatters to the specified array. The array should contain configured instances of NSDateFormatter in the order in which you want them applied during object mapping operations. + + @param dateFormatters An array of date formatters to replace the existing defaults. + @see `defaultDateFormatters` + */ ++ (void)setDefaultDateFormatters:(NSArray *)dateFormatters DEPRECATED_ATTRIBUTE_MESSAGE("Configure `[RKValueTransformer defaultValueTransformer]` instead"); + +/** + **Deprecated in v0.21.0** + + This methods prepends the given date formatter to `[RKValueTransformer defaultValueTransformer]`. + + Adds a date formatter instance to the default collection + + @param dateFormatter An `NSFormatter` object to prepend to the default formatters collection + @see `defaultDateFormatters` + */ ++ (void)addDefaultDateFormatter:(NSFormatter *)dateFormatter DEPRECATED_ATTRIBUTE_MESSAGE("Configure `[RKValueTransformer defaultValueTransformer]` instead"); + +/** + **Deprecated in v0.21.0** + + This method instantiates a new `NSDateFormatter` object with the given format string and time zone and prepends it to `[RKValueTransformer defaultValueTransformer]`. + + Convenience method for quickly constructing a date formatter and adding it to the collection of default date formatters. The locale is auto-configured to `en_US_POSIX`. + + @param dateFormatString The dateFormat string to assign to the newly constructed `NSDateFormatter` instance + @param nilOrTimeZone The NSTimeZone object to configure on the `NSDateFormatter` instance. Defaults to UTC time. + @see `NSDateFormatter` + */ ++ (void)addDefaultDateFormatterForString:(NSString *)dateFormatString inTimeZone:(NSTimeZone *)nilOrTimeZone DEPRECATED_ATTRIBUTE_MESSAGE("Configure `[RKValueTransformer defaultValueTransformer]` instead"); + +/** + **Deprecated in v0.21.0** + + This method returns the first `NSString` -> `NSDate` value transformer that is an instance of `NSFormatter` in `[RKValueTransformer defaultValueTransformer]`. + + Returns the preferred date formatter to use when generating NSString representations from NSDate attributes. This type of transformation occurs when RestKit is mapping local objects into JSON or form encoded serializations that do not have a native time construct. + + Defaults to an instance of the `RKISO8601DateFormatter` configured with the UTC time-zone. The format string is equal to "yyyy-MM-DDThh:mm:ssTZD" + + For details about the ISO-8601 format, see http://www.w3.org/TR/NOTE-datetime + + @return The preferred NSFormatter object to use when serializing dates into strings + */ ++ (NSFormatter *)preferredDateFormatter DEPRECATED_ATTRIBUTE_MESSAGE("Access `[RKValueTransformer defaultValueTransformer]` instead"); + +/** + **Deprecated in v0.21.0** + + This method inserts the given date formatter at position zero in `[RKValueTransformer defaultValueTransformer]`, ensuring that it will be used for all transformations from `NSDate` -> `NSString`. + + Sets the preferred date formatter to use when generating NSString representations from NSDate attributes. This type of transformation occurs when RestKit is mapping local objects into JSON or form encoded serializations that do not have a native time construct. + + @param dateFormatter The NSFormatter object to designate as the new preferred instance + */ ++ (void)setPreferredDateFormatter:(NSFormatter *)dateFormatter DEPRECATED_ATTRIBUTE_MESSAGE("Configure `[RKValueTransformer defaultValueTransformer]` instead"); + +///---------------------------------- +/// @name Configuring Date Formatters +///---------------------------------- + +/** + **Deprecated in v0.21.0** + + An array of `NSFormatter` objects to use when mapping string values into `NSDate` attributes on the target `objectClass`. Each date formatter will be invoked with the string value being mapped until one of the date formatters does not return nil. + + Defaults to the application-wide collection of date formatters configured via `[RKObjectMapping setDefaultDateFormatters:]` + + @see `[RKObjectMapping defaultDateFormatters]` + */ +@property (nonatomic, strong) NSArray *dateFormatters DEPRECATED_ATTRIBUTE_MESSAGE("Use `valueTransformer` instead"); + +/** + **Deprecated in v0.21.0** + + The `NSFormatter` object for your application's preferred date and time configuration. This date formatter will be used when generating string representations of NSDate attributes (i.e. during serialization to URL form encoded or JSON format). + + Defaults to the application-wide preferred date formatter configured via: `[RKObjectMapping setPreferredDateFormatter:]` + + @see `[RKObjectMapping preferredDateFormatter]` + */ +@property (nonatomic, strong) NSFormatter *preferredDateFormatter DEPRECATED_ATTRIBUTE_MESSAGE("Use `valueTransformer` instead"); + +@end + +@interface RKObjectMapping (Deprecations) +// These methods were named to be more idiomation. Properties beginning with `set` generate method names like `setSetDefaultValueForMissingAttributes` and `performKeyValueValidation` reads more as a command to perform something than a configuration switch. +@property (nonatomic, assign, getter = shouldSetDefaultValueForMissingAttributes) BOOL setDefaultValueForMissingAttributes DEPRECATED_ATTRIBUTE_MESSAGE("Renamed to `assignsDefaultValueForMissingAttributes`"); +@property (nonatomic, assign) BOOL setNilForMissingRelationships DEPRECATED_ATTRIBUTE_MESSAGE("Renamed to `assignsNilForMissingRelationships`"); +@property (nonatomic, assign) BOOL performKeyValueValidation DEPRECATED_ATTRIBUTE_MESSAGE("Renamed to `performsKeyValueValidation`"); +@end + +///---------------- +/// @name Functions +///---------------- + +/** + Returns an date representation of a given string value by attempting to parse the string with all default date formatters in turn. + + @param dateString A string object encoding a date value. + @return An `NSDate` object parsed from the given string, or `nil` if the string was found to be unparsable by all default date formatters. + @see [RKObjectMapping defaultDateFormatters] + */ +NSDate *RKDateFromString(NSString *dateString); + +/** + Returns a string representation of a given date formatted with the preferred date formatter. + + This is a convenience function that is equivalent to the following example code: + + NSString *string = [[RKObjectMapping preferredDateFormatter] stringForObjectValue:date] + + @param date The date object to be formatted. + @return An `NSString` object representation of the given date formatted by the preferred date formatter. + @see [RKObjectMapping preferredDateFormatter] + */ +NSString *RKStringFromDate(NSDate *date); diff --git a/Pods/RestKit/Code/ObjectMapping/RKObjectMapping.m b/Pods/RestKit/Code/ObjectMapping/RKObjectMapping.m new file mode 100644 index 0000000..74243b4 --- /dev/null +++ b/Pods/RestKit/Code/ObjectMapping/RKObjectMapping.m @@ -0,0 +1,616 @@ +// +// RKObjectMapping.m +// RestKit +// +// Created by Blake Watters on 4/30/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import <CoreFoundation/CoreFoundation.h> +#import "RKObjectMapping.h" +#import "RKRelationshipMapping.h" +#import "RKPropertyInspector.h" +#import "RKLog.h" +#import "RKAttributeMapping.h" +#import "RKRelationshipMapping.h" +#import "RKValueTransformers.h" +#import "ISO8601DateFormatterValueTransformer.h" + +typedef NSString * (^RKSourceToDesinationKeyTransformationBlock)(RKObjectMapping *, NSString *); + +// Constants +NSString * const RKObjectMappingNestingAttributeKeyName = @"<RK_NESTING_ATTRIBUTE>"; + +static RKSourceToDesinationKeyTransformationBlock defaultSourceToDestinationKeyTransformationBlock = nil; + +@interface RKObjectMapping (Copying) +- (void)copyPropertiesFromMapping:(RKObjectMapping *)mapping; +@end + +@interface RKMappingInverter : NSObject +@property (nonatomic, strong) RKObjectMapping *mapping; +@property (nonatomic, strong) NSMutableDictionary *invertedMappings; + +- (instancetype)initWithMapping:(RKObjectMapping *)mapping; +- (RKObjectMapping *)inverseMappingWithPredicate:(BOOL (^)(RKPropertyMapping *propertyMapping))predicate; +@end + +@implementation RKMappingInverter + +- (instancetype)initWithMapping:(RKObjectMapping *)mapping +{ + self = [self init]; + if (self) { + self.mapping = mapping; + self.invertedMappings = [NSMutableDictionary dictionary]; + } + return self; +} + +- (RKObjectMapping *)invertMapping:(RKObjectMapping *)mapping withPredicate:(BOOL (^)(RKPropertyMapping *propertyMapping))predicate +{ + // Use an NSValue to obtain a non-copied key into our inversed mappings dictionary + NSValue *dictionaryKey = [NSValue valueWithNonretainedObject:mapping]; + RKObjectMapping *inverseMapping = (self.invertedMappings)[dictionaryKey]; + if (inverseMapping) return inverseMapping; + + inverseMapping = [RKObjectMapping requestMapping]; + (self.invertedMappings)[dictionaryKey] = inverseMapping; + [inverseMapping copyPropertiesFromMapping:mapping]; + // We want to serialize `nil` values + inverseMapping.assignsDefaultValueForMissingAttributes = YES; + + for (RKAttributeMapping *attributeMapping in mapping.attributeMappings) { + if (predicate && !predicate(attributeMapping)) continue; + [inverseMapping addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:attributeMapping.destinationKeyPath toKeyPath:attributeMapping.sourceKeyPath]]; + } + + for (RKRelationshipMapping *relationshipMapping in mapping.relationshipMappings) { + RKObjectMapping *mapping = (RKObjectMapping *) relationshipMapping.mapping; + if (! [mapping isKindOfClass:[RKObjectMapping class]]) { + RKLogWarning(@"Unable to generate inverse mapping for relationship '%@': %@ relationships cannot be inversed.", relationshipMapping.sourceKeyPath, NSStringFromClass([mapping class])); + continue; + } + if (predicate && !predicate(relationshipMapping)) continue; + RKMapping *inverseRelationshipMapping = [self invertMapping:mapping withPredicate:predicate]; + if (inverseRelationshipMapping) [inverseMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:relationshipMapping.destinationKeyPath toKeyPath:relationshipMapping.sourceKeyPath withMapping:inverseRelationshipMapping]]; + } + + return inverseMapping; +} + +- (RKObjectMapping *)inverseMappingWithPredicate:(BOOL (^)(RKPropertyMapping *propertyMapping))predicate +{ + return [self invertMapping:self.mapping withPredicate:predicate]; +} + +@end + +@interface RKPropertyMapping () +@property (nonatomic, weak, readwrite) RKObjectMapping *objectMapping; +@end + +@interface RKObjectMapping () +@property (nonatomic, weak, readwrite) Class objectClass; +@property (nonatomic, copy, readwrite) NSArray *propertyMappings; + +@property (nonatomic, strong) NSArray *relationshipMappings; +@property (nonatomic, strong) NSArray *attributeMappings; +@property (nonatomic, strong) NSArray *keyAttributeMappings; +@property (nonatomic, strong) NSArray *keyPathAttributeMappings; +@property (nonatomic, strong) NSMutableDictionary *propertiesBySourceKeyPath; +@property (nonatomic, strong) NSMutableDictionary *propertiesByDestinationKeyPath; + +@property (nonatomic, weak, readonly) NSArray *mappedKeyPaths; +@property (nonatomic, copy) RKSourceToDesinationKeyTransformationBlock sourceToDestinationKeyTransformationBlock; +@end + +@implementation RKObjectMapping + ++ (instancetype)mappingForClass:(Class)objectClass +{ + return [[self alloc] initWithClass:objectClass]; +} + ++ (RKObjectMapping *)requestMapping +{ + if (! [self isEqual:[RKObjectMapping class]]) { + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:[NSString stringWithFormat:@"`%@` is not meant to be invoked on `%@`. You probably want to invoke `[RKObjectMapping requestMapping]`.", + NSStringFromSelector(_cmd), + NSStringFromClass(self)] + userInfo:nil]; + } + + // TODO: Hook up value transformers from `RKObjectParameterization` + RKObjectMapping *objectMapping = [self mappingForClass:[NSMutableDictionary class]]; + objectMapping.assignsDefaultValueForMissingAttributes = YES; + return objectMapping; +} + ++ (void)initialize +{ + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + // Add an ISO8601DateFormatter to the transformation stack for backwards compatibility + RKISO8601DateFormatter *dateFormatter = [RKISO8601DateFormatter defaultISO8601DateFormatter]; + [[RKValueTransformer defaultValueTransformer] insertValueTransformer:dateFormatter atIndex:0]; + }); +} + +- (instancetype)initWithClass:(Class)objectClass +{ + self = [super init]; + if (self) { + self.objectClass = objectClass; + self.propertyMappings = [NSArray new]; + self.relationshipMappings = [NSArray new]; + self.attributeMappings = [NSArray new]; + self.keyAttributeMappings = [NSArray new]; + self.keyPathAttributeMappings = [NSArray new]; + self.propertiesBySourceKeyPath = [NSMutableDictionary new]; + self.propertiesByDestinationKeyPath = [NSMutableDictionary new]; + self.assignsDefaultValueForMissingAttributes = NO; + self.assignsNilForMissingRelationships = NO; + self.forceCollectionMapping = NO; + self.performsKeyValueValidation = YES; + self.sourceToDestinationKeyTransformationBlock = defaultSourceToDestinationKeyTransformationBlock; + self.valueTransformer = [[RKValueTransformer defaultValueTransformer] copy]; + } + + return self; +} + +- (void)copyPropertiesFromMapping:(RKObjectMapping *)mapping +{ + self.assignsDefaultValueForMissingAttributes = mapping.assignsDefaultValueForMissingAttributes; + self.assignsNilForMissingRelationships = mapping.assignsNilForMissingRelationships; + self.forceCollectionMapping = mapping.forceCollectionMapping; + self.performsKeyValueValidation = mapping.performsKeyValueValidation; + self.valueTransformer = mapping.valueTransformer; + self.sourceToDestinationKeyTransformationBlock = mapping.sourceToDestinationKeyTransformationBlock; +} + +- (id)copyWithZone:(NSZone *)zone +{ + RKObjectMapping *copy = [[[self class] allocWithZone:zone] initWithClass:self.objectClass]; + [copy copyPropertiesFromMapping:self]; + + for (RKPropertyMapping *propertyMapping in self.propertyMappings) { + [copy addPropertyMapping:[propertyMapping copy]]; + } + + return copy; +} + ++ (void)setDefaultSourceToDestinationKeyTransformationBlock:(RKSourceToDesinationKeyTransformationBlock)block +{ + defaultSourceToDestinationKeyTransformationBlock = block; +} + +- (NSDictionary *)propertyMappingsBySourceKeyPath +{ + return [self.propertiesBySourceKeyPath copy]; +} + +- (NSDictionary *)propertyMappingsByDestinationKeyPath +{ + return [self.propertiesByDestinationKeyPath copy]; +} + +- (NSArray *)mappedKeyPaths +{ + return [self.propertyMappings valueForKey:@"destinationKeyPath"]; +} + +- (NSArray *)attributeMappings +{ + return _attributeMappings; +} + +- (NSArray *)relationshipMappings +{ + return _relationshipMappings; +} + +- (NSArray *)keyAttributeMappings +{ + return _keyAttributeMappings; +} + +- (NSArray *)keyPathAttributeMappings +{ + return _keyPathAttributeMappings; +} + +static NSArray *RKAddProperty(NSArray *array, RKPropertyMapping *mapping) +{ + return (array)? [array arrayByAddingObject:mapping] : @[mapping]; +} + +static NSArray *RKRemoveProperty(NSArray *array, RKPropertyMapping *mapping) +{ + if (![array containsObject:mapping]) return array; + NSMutableArray *mappings = [[NSMutableArray alloc] initWithArray:array]; //alloc/init avoids autorelease + [mappings removeObject:mapping]; + return [mappings copy]; +} + +- (void)addPropertyMapping:(RKPropertyMapping *)propertyMapping +{ + NSAssert1([[self mappedKeyPaths] containsObject:propertyMapping.destinationKeyPath] == NO, + @"Unable to add mapping for keyPath %@, one already exists...", propertyMapping.destinationKeyPath); + NSAssert(self.propertyMappings, @"self.propertyMappings is nil"); + NSAssert(propertyMapping.objectMapping == nil, @"Cannot add a property mapping object that has already been added to another `RKObjectMapping` object. You probably want to obtain a copy of the mapping: `[propertyMapping copy]`"); + propertyMapping.objectMapping = self; + self.propertyMappings = [self.propertyMappings arrayByAddingObject:propertyMapping]; + [self.propertiesBySourceKeyPath setObject:propertyMapping forKey:propertyMapping.sourceKeyPath ?: [NSNull null]]; + if (propertyMapping.destinationKeyPath) (self.propertiesByDestinationKeyPath)[propertyMapping.destinationKeyPath] = propertyMapping; + if ([propertyMapping isMemberOfClass:[RKRelationshipMapping class]]) { + self.relationshipMappings = RKAddProperty(self.relationshipMappings, propertyMapping); + } + else if ([propertyMapping isMemberOfClass:[RKAttributeMapping class]]) + { + self.attributeMappings = RKAddProperty(self.attributeMappings, propertyMapping); + if ([propertyMapping.sourceKeyPath rangeOfString:@"." options:NSLiteralSearch].length == 0) { + self.keyAttributeMappings = RKAddProperty(self.keyAttributeMappings, propertyMapping); + } + else { + self.keyPathAttributeMappings = RKAddProperty(self.keyPathAttributeMappings, propertyMapping); + } + } + + if (propertyMapping.propertyValueClass == Nil && ![self.objectClass isSubclassOfClass:[NSDictionary class]]) { + propertyMapping.propertyValueClass = [self classForKeyPath:propertyMapping.destinationKeyPath]; + } +} + +- (void)addPropertyMappingsFromArray:(NSArray *)arrayOfPropertyMappings +{ + NSAssert([[arrayOfPropertyMappings valueForKeyPath:@"@distinctUnionOfObjects.objectMapping"] count] == 0, @"One or more of the property mappings in the given array has already been added to another `RKObjectMapping` object. You probably want to obtain a copy of the array of mappings: `[[NSArray alloc] initWithArray:arrayOfPropertyMappings copyItems:YES]`"); + for (RKPropertyMapping *propertyMapping in arrayOfPropertyMappings) { + [self addPropertyMapping:propertyMapping]; + } +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@"<%@:%p objectClass=%@ propertyMappings=%@>", + NSStringFromClass([self class]), self, NSStringFromClass(self.objectClass), self.propertyMappings]; +} + +- (id)mappingForSourceKeyPath:(NSString *)sourceKeyPath +{ + return _propertiesBySourceKeyPath[sourceKeyPath ?: [NSNull null]]; +} + +- (id)mappingForDestinationKeyPath:(NSString *)destinationKeyPath +{ + return _propertiesByDestinationKeyPath[destinationKeyPath]; +} + +// Evaluate each component individually so that camelization, etc. considers each component individually +- (NSString *)transformSourceKeyPath:(NSString *)keyPath +{ + if (!self.sourceToDestinationKeyTransformationBlock) return keyPath; + + NSRange dotRange = [keyPath rangeOfString:@"." options:NSLiteralSearch]; + if (dotRange.length == 0) { + return self.sourceToDestinationKeyTransformationBlock(self, keyPath); + } + + NSArray *components = [keyPath componentsSeparatedByString:@"."]; + NSMutableArray *mutableComponents = [NSMutableArray arrayWithCapacity:[components count]]; + [components enumerateObjectsUsingBlock:^(id component, NSUInteger idx, BOOL *stop) { + [mutableComponents addObject:self.sourceToDestinationKeyTransformationBlock(self, component)]; + }]; + + return [mutableComponents componentsJoinedByString:@"."]; +} + +- (void)addAttributeMappingsFromDictionary:(NSDictionary *)keyPathToAttributeNames +{ + for (NSString *attributeKeyPath in keyPathToAttributeNames) { + [self addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:attributeKeyPath toKeyPath:keyPathToAttributeNames[attributeKeyPath]]]; + } +} + +- (void)addAttributeMappingsFromArray:(NSArray *)arrayOfAttributeNamesOrMappings +{ + NSMutableArray *arrayOfAttributeMappings = [NSMutableArray arrayWithCapacity:[arrayOfAttributeNamesOrMappings count]]; + for (id entry in arrayOfAttributeNamesOrMappings) { + if ([entry isKindOfClass:[NSString class]]) { + NSString *destinationKeyPath = [self transformSourceKeyPath:entry]; + [arrayOfAttributeMappings addObject:[RKAttributeMapping attributeMappingFromKeyPath:entry toKeyPath:destinationKeyPath]]; + } else if ([entry isKindOfClass:[RKAttributeMapping class]]) { + [arrayOfAttributeMappings addObject:entry]; + } else { + [NSException raise:NSInvalidArgumentException + format:@"*** - [%@ %@]: Unable to attribute mapping from unsupported entry of type '%@' (%@).", NSStringFromClass([self class]), NSStringFromSelector(_cmd), NSStringFromClass([entry class]), entry]; + } + } + + [self addPropertyMappingsFromArray:arrayOfAttributeMappings]; +} + +- (void)addRelationshipMappingWithSourceKeyPath:(NSString *)sourceKeyPath mapping:(RKMapping *)mapping +{ + NSParameterAssert(sourceKeyPath); + NSParameterAssert(mapping); + + NSString *destinationKeyPath = [self transformSourceKeyPath:sourceKeyPath]; + RKRelationshipMapping *relationshipMapping = [RKRelationshipMapping relationshipMappingFromKeyPath:sourceKeyPath toKeyPath:destinationKeyPath withMapping:mapping]; + [self addPropertyMapping:relationshipMapping]; +} + +- (void)removePropertyMapping:(RKPropertyMapping *)attributeOrRelationshipMapping +{ + if ([self.propertyMappings containsObject:attributeOrRelationshipMapping]) { + attributeOrRelationshipMapping.objectMapping = nil; + self.propertyMappings = RKRemoveProperty(self.propertyMappings, attributeOrRelationshipMapping); + self.relationshipMappings = RKRemoveProperty(self.relationshipMappings, attributeOrRelationshipMapping); + self.attributeMappings = RKRemoveProperty(self.attributeMappings, attributeOrRelationshipMapping); + self.keyAttributeMappings = RKRemoveProperty(self.keyAttributeMappings, attributeOrRelationshipMapping); + self.keyPathAttributeMappings = RKRemoveProperty(self.keyPathAttributeMappings, attributeOrRelationshipMapping); + [self.propertiesBySourceKeyPath removeObjectForKey:attributeOrRelationshipMapping.sourceKeyPath ?: [NSNull null]]; + [self.propertiesByDestinationKeyPath removeObjectForKey:attributeOrRelationshipMapping.destinationKeyPath ?: [NSNull null]]; + } +} + +- (instancetype)inverseMappingWithPropertyMappingsPassingTest:(BOOL (^)(RKPropertyMapping *propertyMapping))predicate +{ + RKMappingInverter *mappingInverter = [[RKMappingInverter alloc] initWithMapping:self]; + return [mappingInverter inverseMappingWithPredicate:predicate]; +} + +- (instancetype)inverseMapping +{ + return [self inverseMappingWithPropertyMappingsPassingTest:nil]; +} + +- (void)addAttributeMappingFromKeyOfRepresentationToAttribute:(NSString *)attributeName +{ + [self addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:RKObjectMappingNestingAttributeKeyName toKeyPath:attributeName]]; +} + +- (void)addAttributeMappingToKeyOfRepresentationFromAttribute:(NSString *)attributeName +{ + [self addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:attributeName toKeyPath:RKObjectMappingNestingAttributeKeyName]]; +} + +- (RKAttributeMapping *)mappingForAttribute:(NSString *)attributeKey +{ + for (RKAttributeMapping *mapping in [self attributeMappings]) { + if ([mapping.destinationKeyPath isEqualToString:attributeKey]) { + return mapping; + } + } + + return nil; +} + +- (RKRelationshipMapping *)mappingForRelationship:(NSString *)relationshipKey +{ + for (RKRelationshipMapping *mapping in [self relationshipMappings]) { + if ([mapping.destinationKeyPath isEqualToString:relationshipKey]) { + return mapping; + } + } + + return nil; +} + +- (id)defaultValueForAttribute:(NSString *)attributeName +{ + return nil; +} + +- (Class)classForProperty:(NSString *)propertyName +{ + return [[RKPropertyInspector sharedInspector] classForPropertyNamed:propertyName ofClass:self.objectClass isPrimitive:nil]; +} + +- (Class)classForKeyPath:(NSString *)keyPath +{ + if (keyPath == nil) return self.objectClass; + + RKPropertyInspector *inspector = [RKPropertyInspector sharedInspector]; + + if ([keyPath rangeOfString:@"." options:NSLiteralSearch].length == 0) { + return [inspector classForPropertyNamed:keyPath ofClass:self.objectClass isPrimitive:nil]; + } + + NSArray *components = [keyPath componentsSeparatedByString:@"."]; + Class propertyClass = self.objectClass; + for (NSString *property in components) { + propertyClass = [inspector classForPropertyNamed:property ofClass:propertyClass isPrimitive:nil]; + if (! propertyClass) break; + } + + return propertyClass; +} + +- (BOOL)isEqualToMapping:(RKObjectMapping *)otherMapping +{ + if (! [otherMapping isKindOfClass:[RKObjectMapping class]]) return NO; + if ((self.objectClass && otherMapping.objectClass) && + ! [otherMapping.objectClass isEqual:self.objectClass]) { + return NO; + } else if (self.objectClass != nil && otherMapping.objectClass == nil) { + return NO; + } else if (self.objectClass == nil && otherMapping.objectClass != nil) { + return NO; + } + + // Check that the number of attribute/relationship mappings is equal and compare all + if ([self.propertyMappings count] != [otherMapping.propertyMappings count]) return NO; + + for (RKPropertyMapping *propertyMapping in self.propertyMappings) { + RKPropertyMapping *otherPropertyMapping = [otherMapping mappingForSourceKeyPath:propertyMapping.sourceKeyPath]; + if (! [propertyMapping isEqualToMapping:otherPropertyMapping]) return NO; + } + + return YES; +} + +@end + +///////////////////////////////////////////////////////////////////////////// + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-implementations" + +@implementation RKObjectMapping (LegacyDateAndTimeFormatting) + ++ (NSArray *)defaultDateFormatters +{ + NSArray *valueTransformers = [[RKValueTransformer defaultValueTransformer] valueTransformersForTransformingFromClass:[NSString class] toClass:[NSDate class]]; + NSMutableArray *dateFormatters = [NSMutableArray arrayWithCapacity:[valueTransformers count]]; + for (id<RKValueTransforming> valueTransformer in valueTransformers) { + if ([valueTransformer respondsToSelector:@selector(dateFromString:)]) [dateFormatters addObject:valueTransformer]; + } + return dateFormatters; +} + ++ (void)setDefaultDateFormatters:(NSArray *)dateFormatters +{ + NSArray *defaultDateFormatters = [self defaultDateFormatters]; + for (NSDateFormatter *dateFormatter in defaultDateFormatters) { + [[RKValueTransformer defaultValueTransformer] removeValueTransformer:dateFormatter]; + } + + for (NSDateFormatter *dateFormatter in dateFormatters) { + [[RKValueTransformer defaultValueTransformer] addValueTransformer:dateFormatter]; + } +} + ++ (void)addDefaultDateFormatter:(id)dateFormatter +{ + [[RKValueTransformer defaultValueTransformer] insertValueTransformer:dateFormatter atIndex:0]; +} + ++ (void)addDefaultDateFormatterForString:(NSString *)dateFormatString inTimeZone:(NSTimeZone *)nilOrTimeZone +{ + NSDateFormatter *dateFormatter = [NSDateFormatter new]; + dateFormatter.dateFormat = dateFormatString; + dateFormatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"]; + dateFormatter.timeZone = nilOrTimeZone ?: [NSTimeZone timeZoneWithAbbreviation:@"UTC"]; + [self addDefaultDateFormatter:dateFormatter]; +} + ++ (NSFormatter *)preferredDateFormatter +{ + NSArray *defaultDateFormatters = [self defaultDateFormatters]; + return [defaultDateFormatters count] ? defaultDateFormatters[0] : nil; +} + ++ (void)setPreferredDateFormatter:(NSDateFormatter *)dateFormatter +{ + [[RKValueTransformer defaultValueTransformer] insertValueTransformer:dateFormatter atIndex:0]; +} + +#pragma mark - Date and Time + +- (NSFormatter *)preferredDateFormatter +{ + if ([self.valueTransformer isKindOfClass:[RKCompoundValueTransformer class]]) { + NSArray *dateToStringTransformers = [(RKCompoundValueTransformer *)self.valueTransformer valueTransformersForTransformingFromClass:[NSDate class] toClass:[NSString class]]; + for (id<RKValueTransforming> valueTransformer in dateToStringTransformers) { + if ([valueTransformer isKindOfClass:[NSFormatter class]]) return (NSFormatter *)valueTransformer; + } + } + return nil; +} + +- (void)setPreferredDateFormatter:(NSFormatter *)preferredDateFormatter +{ + if ([self.valueTransformer isKindOfClass:[RKCompoundValueTransformer class]]) { + [(RKCompoundValueTransformer *)self.valueTransformer insertValueTransformer:(NSFormatter<RKValueTransforming> *)preferredDateFormatter atIndex:0]; + } +} + +- (NSArray *)dateFormatters +{ + if ([self.valueTransformer isKindOfClass:[RKCompoundValueTransformer class]]) { + return [(RKCompoundValueTransformer *)self.valueTransformer valueTransformersForTransformingFromClass:[NSDate class] toClass:[NSString class]]; + } else return nil; +} + +- (void)setDateFormatters:(NSArray *)dateFormatters +{ + if (! [self.valueTransformer isKindOfClass:[RKCompoundValueTransformer class]]) [NSException raise:NSInternalInconsistencyException format:@"Cannot set date formatters: the receiver's `valueTransformer` is not an instance of `RKCompoundValueTransformer`."]; + for (id<RKValueTransforming> dateFormatter in [self dateFormatters]) { + [(RKCompoundValueTransformer *)self.valueTransformer removeValueTransformer:dateFormatter]; + } + for (id<RKValueTransforming> dateFormatter in dateFormatters) { + [(RKCompoundValueTransformer *)self.valueTransformer addValueTransformer:dateFormatter]; + } +} + +@end + +@implementation RKObjectMapping (Deprecations) + +- (BOOL)shouldSetDefaultValueForMissingAttributes +{ + return self.assignsDefaultValueForMissingAttributes; +} + +- (void)setSetDefaultValueForMissingAttributes:(BOOL)setDefaultValueForMissingAttributes +{ + self.assignsDefaultValueForMissingAttributes = setDefaultValueForMissingAttributes; +} + +- (BOOL)setNilForMissingRelationships +{ + return self.assignsNilForMissingRelationships; +} + +- (void)setSetNilForMissingRelationships:(BOOL)setNilForMissingRelationships +{ + self.assignsNilForMissingRelationships = setNilForMissingRelationships; +} + +- (BOOL)performKeyValueValidation +{ + return self.performsKeyValueValidation; +} + +- (void)setPerformKeyValueValidation:(BOOL)performKeyValueValidation +{ + self.performsKeyValueValidation = performKeyValueValidation; +} + +@end + +#pragma clang diagnostic pop + +#pragma mark - Functions + +NSDate *RKDateFromString(NSString *dateString) +{ + NSDate *outputDate = nil; + NSError *error = nil; + BOOL success = [[RKValueTransformer defaultValueTransformer] transformValue:dateString toValue:&outputDate ofClass:[NSDate class] error:&error]; + return success ? outputDate : nil; +} + +NSString *RKStringFromDate(NSDate *date) +{ + NSString *outputString = nil; + NSError *error = nil; + BOOL success = [[RKValueTransformer defaultValueTransformer] transformValue:date toValue:&outputString ofClass:[NSString class] error:&error]; + return success ? outputString : nil; +} diff --git a/Pods/RestKit/Code/ObjectMapping/RKObjectMappingMatcher.h b/Pods/RestKit/Code/ObjectMapping/RKObjectMappingMatcher.h new file mode 100644 index 0000000..577550c --- /dev/null +++ b/Pods/RestKit/Code/ObjectMapping/RKObjectMappingMatcher.h @@ -0,0 +1,112 @@ +// +// RKDynamicMappingMatcher.h +// RestKit +// +// Created by Jeff Arena on 8/2/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// + +#import <Foundation/Foundation.h> +#import "RKObjectMapping.h" + +/** + The `RKObjectMappingMatcher` class provides an interface for encapsulating the selection of an object mapping based on runtime values. Matcher objects may be configured by key path and expected value or with a predicate object. + + ## Key Path Matching + + A key path matcher object is initialized with a key path, an expected value to be read from the key path, and an object mapping that is to be applied if the match evaluates to `YES`. When evaluating the match, the matcher invokes `valueForKeyPath:` on the object being matched and compares the value returned with the `expectedValue` via the `RKObjectIsEqualToObject` function. This provides a flexible, semantic match of the property value. + + Alternatively, a key path matcher object can be initialized with an expected class instead. When evaluating the match, the matcher invokes `valueForKeyPath:` on the object being matched and compares the value returned with the `expectedClass` via the `isSubclassOfClass:` method. This provides a flexible, semantic match of the property value class. + + ## Predicate Matching + + A predicate matcher object is initialized with a predicate object and an object mapping that is to be applied if the predicate evaluates to `YES` for the object being matched. + */ +@interface RKObjectMappingMatcher : NSObject + +///------------------------------------- +/// @name Constructing Key Path Matchers +///------------------------------------- + +/** + Creates and returns a key path matcher object with a given key path, expected value, and an object mapping that applies in the event of a positive match. + + @param keyPath The key path to obtain the comparison value from the object being matched via `valueForKeyPath:`. + @param expectedValue The value that is expected to be read from `keyPath` if there is a match. + @param objectMapping The object mapping object that applies if the comparison value is equal to the expected value. + @return The receiver, initialized with the given key path, expected value, and object mapping. + */ ++ (instancetype)matcherWithKeyPath:(NSString *)keyPath expectedValue:(id)expectedValue objectMapping:(RKObjectMapping *)objectMapping; + +/** + Creates and returns a key path matcher object with a given key path, expected class, and an object mapping that applies in the event of a positive match. + + @param keyPath The key path to obtain the comparison value from the object being matched via `valueForKeyPath:`. + @param expectedClass The Class that is expected to be read from `keyPath` if there is a match. + @param objectMapping The object mapping object that applies if the comparison value is equal to the expected value. + @return The receiver, initialized with the given key path, expected value, and object mapping. + */ ++ (instancetype)matcherWithKeyPath:(NSString *)keyPath expectedClass:(Class)expectedClass objectMapping:(RKObjectMapping *)objectMapping; + +/** + Creates and returns a key path matcher object with a given key path, and a map of expected values to associated RKObjectMapping objects that applies in the event of a positive match with its associated value. This method can evaluate the keyPath once + + @param keyPath The key path to obtain the comparison value from the object being matched via `valueForKeyPath:`. + @param expectedValue The value that is expected to be read from `keyPath` if there is a match. + @param objectMapping The object mapping object that applies if the comparison value is equal to the expected value. + @return The receiver, initialized with the given key path and expected value map. + */ ++ (instancetype)matcherWithKeyPath:(NSString *)keyPath expectedValueMap:(NSDictionary *)valueToObjectMapping; + +///-------------------------------------- +/// @name Constructing Predicate Matchers +///-------------------------------------- + +/** + Creates and returns a predicate matcher object with a given predicate and an object mapping that applies in the predicate evaluates positively. + + @param predicate The predicate with which to evaluate the matched object. + @param objectMapping The object mapping object that applies if the predicate evaluates positively for the matched object. + @return The receiver, initialized with the given key path, expected value, and object mapping. + */ ++ (instancetype)matcherWithPredicate:(NSPredicate *)predicate objectMapping:(RKObjectMapping *)objectMapping; + + +/** + Creates and returns a matcher object with a given block which returns the RKObjectMapping instance to use, and an optional array of possible object mappings which could be returned. + + @param possibleMappings The list of known possible RKObjectMapping instances which could be returned. This is used to aid RKDynamicMapping's -objectMappings method which is used in some instances, but is not required for mapping. The block could return a new instance if needed. + @param block The block with which to evaluate the matched object, and return the object mapping to use. Return nil if no match (i.e. a `NO` return from the `-matches:` method). + @return The receiver, initialized with the given block ans possible mappings. + */ ++ (instancetype)matcherWithPossibleMappings:(NSArray *)mappings block:(RKObjectMapping *(^)(id representation))block; + +///----------------------------------- +/// @name Accessing the Object Mapping +///----------------------------------- + +/** + Returns the list of all known RKObjectMapping instances which could be returned from this matcher. This is called when added to or removed from an RKDynamicMapping, and is used to populate the `objectMappings` property there. The default implementation returns the single value set in the `objectMapping` property, so if that is the only possibility then this method does not need to be overridden. + */ +@property (nonatomic, readonly) NSArray *possibleObjectMappings; + +/** + The object mapping object that applies when the receiver matches a given object. + + @see `matches:` + */ +@property (nonatomic, strong, readonly) RKObjectMapping *objectMapping; + +///------------------------- +/// @name Evaluating a Match +///------------------------- + +/** + Returns a Boolean value that indicates if the given object matches the expectations of the receiver. + + @param object The object to be evaluated. + @return `YES` if the object matches the expectations of the receiver, else `NO`. + */ +- (BOOL)matches:(id)object; + +@end diff --git a/Pods/RestKit/Code/ObjectMapping/RKObjectMappingMatcher.m b/Pods/RestKit/Code/ObjectMapping/RKObjectMappingMatcher.m new file mode 100644 index 0000000..4efebc3 --- /dev/null +++ b/Pods/RestKit/Code/ObjectMapping/RKObjectMappingMatcher.m @@ -0,0 +1,273 @@ +// +// RKDynamicMappingMatcher.m +// RestKit +// +// Created by Jeff Arena on 8/2/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// + +#import "RKObjectMappingMatcher.h" +#import "RKObjectUtilities.h" + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +@interface RKObjectMappingMatcher () +@property (nonatomic, strong, readwrite) RKObjectMapping *objectMapping; +@end + +@interface RKKeyPathObjectMappingMatcher : RKObjectMappingMatcher +@property (nonatomic, copy) NSString *keyPath; +@property (nonatomic, strong, readwrite) id expectedValue; + +- (instancetype)initWithKeyPath:(NSString *)keyPath expectedValue:(id)expectedValue objectMapping:(RKObjectMapping *)objectMapping NS_DESIGNATED_INITIALIZER; +@end + +@interface RKKeyPathClassObjectMappingMatcher : RKObjectMappingMatcher + +@property (nonatomic, copy) NSString *keyPath; +@property (nonatomic, readwrite) Class expectedClass; + +- (instancetype)initWithKeyPath:(NSString *)keyPath expectedClass:(Class)expectedClass objectMapping:(RKObjectMapping *)objectMapping NS_DESIGNATED_INITIALIZER; + +@end + +@interface RKKeyPathValueMapObjectMappingMatcher : RKObjectMappingMatcher +@property (nonatomic, copy) NSString *keyPath; +@property (nonatomic, copy) NSDictionary *valueMap; + +- (instancetype)initWithKeyPath:(NSString *)keyPath expectedValueMap:(NSDictionary *)valueToObjectMapping NS_DESIGNATED_INITIALIZER; +@end + +@interface RKPredicateObjectMappingMatcher : RKObjectMappingMatcher +@property (nonatomic, strong) NSPredicate *predicate; + +- (instancetype)initWithPredicate:(NSPredicate *)predicate objectMapping:(RKObjectMapping *)objectMapping NS_DESIGNATED_INITIALIZER; +@end + +@interface RKBlockObjectMatchingMatcher : RKObjectMappingMatcher +@property (nonatomic, copy) NSArray *possibleMappings; +@property (nonatomic, copy) RKObjectMapping *(^block)(id representation); +- (instancetype)initWithPossibleMappings:(NSArray *)mappings block:(RKObjectMapping *(^)(id representation))block NS_DESIGNATED_INITIALIZER; +@end + + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +@implementation RKObjectMappingMatcher + ++ (instancetype)matcherWithKeyPath:(NSString *)keyPath expectedValue:(id)expectedValue objectMapping:(RKObjectMapping *)objectMapping +{ + return [[RKKeyPathObjectMappingMatcher alloc] initWithKeyPath:keyPath expectedValue:expectedValue objectMapping:objectMapping]; +} + ++ (instancetype)matcherWithKeyPath:(NSString *)keyPath expectedClass:(Class)expectedClass objectMapping:(RKObjectMapping *)objectMapping +{ + return [[RKKeyPathClassObjectMappingMatcher alloc] initWithKeyPath:keyPath expectedClass:expectedClass objectMapping:objectMapping]; +} + ++ (instancetype)matcherWithKeyPath:(NSString *)keyPath expectedValueMap:(NSDictionary *)valueToObjectMapping +{ + return [[RKKeyPathValueMapObjectMappingMatcher alloc] initWithKeyPath:keyPath expectedValueMap:valueToObjectMapping]; +} + ++ (instancetype)matcherWithPredicate:(NSPredicate *)predicate objectMapping:(RKObjectMapping *)objectMapping +{ + return [[RKPredicateObjectMappingMatcher alloc] initWithPredicate:predicate objectMapping:objectMapping]; +} + ++ (instancetype)matcherWithPossibleMappings:(NSArray *)mappings block:(RKObjectMapping *(^)(id representation))block +{ + return [[RKBlockObjectMatchingMatcher alloc] initWithPossibleMappings:mappings block:block]; +} + +- (instancetype)init +{ + self = [super init]; + if (self) { + if ([self isMemberOfClass:[RKObjectMappingMatcher class]]) { + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:[NSString stringWithFormat:@"%@ is not meant to be directly instantiated. Use one of the initializer methods instead.", + NSStringFromClass([self class])] + userInfo:nil]; + } + } + + return self; +} + +- (NSArray *)possibleObjectMappings +{ + RKObjectMapping *mapping = self.objectMapping; + return mapping ? @[mapping] : nil; +} + +- (BOOL)matches:(id)object +{ + return NO; +} + +@end + +@implementation RKKeyPathObjectMappingMatcher + +- (instancetype)initWithKeyPath:(NSString *)keyPath expectedValue:(id)expectedValue objectMapping:(RKObjectMapping *)objectMapping +{ + NSParameterAssert(keyPath); + NSParameterAssert(expectedValue); + NSParameterAssert(objectMapping); + self = [super init]; + if (self) { + self.keyPath = keyPath; + self.expectedValue = expectedValue; + self.objectMapping = objectMapping; + } + + return self; +} + +- (BOOL)matches:(id)object +{ + id value = [object valueForKeyPath:self.keyPath]; + if (value == nil) return NO; + return RKObjectIsEqualToObject(value, self.expectedValue); +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@"<%@: %p when `%@` == '%@' objectMapping: %@>", NSStringFromClass([self class]), self, self.keyPath, self.expectedValue, self.objectMapping]; +} + +@end + +@implementation RKKeyPathClassObjectMappingMatcher + +- (instancetype)initWithKeyPath:(NSString *)keyPath expectedClass:(Class)expectedClass objectMapping:(RKObjectMapping *)objectMapping +{ + NSParameterAssert(keyPath); + NSParameterAssert(expectedClass); + NSParameterAssert(objectMapping); + self = [super init]; + if (self) { + self.keyPath = keyPath; + self.expectedClass = expectedClass; + self.objectMapping = objectMapping; + } + + return self; +} + +- (BOOL)matches:(id)object +{ + id value = [object valueForKeyPath:self.keyPath]; + return [[value class] isSubclassOfClass:self.expectedClass]; +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@"<%@: %p when `%@` == '%@' objectMapping: %@>", NSStringFromClass([self class]), self, self.keyPath, self.expectedClass, self.objectMapping]; +} + +@end + +@implementation RKKeyPathValueMapObjectMappingMatcher + +- (instancetype)initWithKeyPath:(NSString *)keyPath expectedValueMap:(NSDictionary *)valueToObjectMapping +{ + NSParameterAssert(keyPath); + NSParameterAssert(valueToObjectMapping.count > 0); + self = [super init]; + if (self) { + self.keyPath = keyPath; + self.valueMap = valueToObjectMapping; + } + + return self; +} + +- (NSArray *)possibleObjectMappings +{ + return [self.valueMap allValues]; +} + +- (BOOL)matches:(id)object +{ + id value = [object valueForKeyPath:self.keyPath]; + RKObjectMapping *mapping = (self.valueMap)[value]; + if (mapping) { + self.objectMapping = mapping; + return YES; + } + + return NO; +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@"<%@: %p when `%@` in '%@'>", NSStringFromClass([self class]), self, self.keyPath, [self.valueMap allKeys]]; +} + +@end + +@implementation RKPredicateObjectMappingMatcher + +- (instancetype)initWithPredicate:(NSPredicate *)predicate objectMapping:(RKObjectMapping *)objectMapping +{ + NSParameterAssert(predicate); + NSParameterAssert(objectMapping); + self = [super init]; + if (self) { + self.predicate = predicate; + self.objectMapping = objectMapping; + } + + return self; +} + +- (BOOL)matches:(id)object +{ + return [self.predicate evaluateWithObject:object]; +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@"<%@: %p when '%@' objectMapping: %@>", NSStringFromClass([self class]), self, self.predicate, self.objectMapping]; +} + +@end + +@implementation RKBlockObjectMatchingMatcher + +- (instancetype)initWithPossibleMappings:(NSArray *)mappings block:(RKObjectMapping *(^)(id representation))block +{ + NSParameterAssert(block); + self = [super init]; + if (self) { + self.block = block; + self.possibleMappings = mappings; + } + + return self; +} + +- (NSArray *)possibleObjectMappings +{ + return self.possibleMappings; +} + +- (BOOL)matches:(id)object +{ + RKObjectMapping *mapping = self.block(object); + if (mapping) { + self.objectMapping = mapping; + return YES; + } + + return NO; +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@"<%@: %p when '%@'>", NSStringFromClass([self class]), self, self.block]; +} + +@end diff --git a/Pods/RestKit/Code/ObjectMapping/RKObjectMappingOperationDataSource.h b/Pods/RestKit/Code/ObjectMapping/RKObjectMappingOperationDataSource.h new file mode 100644 index 0000000..3daf216 --- /dev/null +++ b/Pods/RestKit/Code/ObjectMapping/RKObjectMappingOperationDataSource.h @@ -0,0 +1,27 @@ +// +// RKObjectMappingOperationDataSource.h +// RestKit +// +// Created by Blake Watters on 7/3/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKMappingOperationDataSource.h" + +/** + The `RKObjectMappingOperationDataSource` class is an implementation of the `RKMappingOperationDataSource` protocol for use in performing object mappings that target plain old `NSObject` derived classes (as opposed to `NSManagedObject` derived persistent entities). + */ +@interface RKObjectMappingOperationDataSource : NSObject <RKMappingOperationDataSource> +@end diff --git a/Pods/RestKit/Code/ObjectMapping/RKObjectMappingOperationDataSource.m b/Pods/RestKit/Code/ObjectMapping/RKObjectMappingOperationDataSource.m new file mode 100644 index 0000000..e8aba71 --- /dev/null +++ b/Pods/RestKit/Code/ObjectMapping/RKObjectMappingOperationDataSource.m @@ -0,0 +1,48 @@ +// +// RKObjectMappingOperationDataSource.m +// RestKit +// +// Created by Blake Watters on 7/3/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKObjectMappingOperationDataSource.h" +#import "RKObjectMapping.h" +#import "RKMappingOperation.h" + +@implementation RKObjectMappingOperationDataSource + +- (id)mappingOperation:(RKMappingOperation *)mappingOperation targetObjectForRepresentation:(NSDictionary *)representation + withMapping:(RKObjectMapping *)mapping inRelationship:(RKRelationshipMapping *)relationshipMapping +{ + return [mapping.objectClass new]; +} + +- (id)mappingOperation:(RKMappingOperation *)mappingOperation targetObjectForMapping:(RKObjectMapping *)mapping inRelationship:(RKRelationshipMapping *)relationshipMapping +{ + return [mapping.objectClass new]; +} + +- (BOOL)mappingOperationShouldCollectMappingInfo:(RKMappingOperation *)mappingOperation +{ + return NO; +} + +- (BOOL)mappingOperationShouldSetUnchangedValues:(RKMappingOperation *)mappingOperation +{ + return [mappingOperation isNewDestinationObject]; +} + +@end diff --git a/Pods/RestKit/Code/ObjectMapping/RKObjectUtilities.h b/Pods/RestKit/Code/ObjectMapping/RKObjectUtilities.h new file mode 100644 index 0000000..d8a4043 --- /dev/null +++ b/Pods/RestKit/Code/ObjectMapping/RKObjectUtilities.h @@ -0,0 +1,113 @@ +// +// RKObjectUtilities.h +// RestKit +// +// Created by Blake Watters on 9/30/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import <Foundation/Foundation.h> + +#ifdef __cplusplus +extern "C" { +#endif + +///---------------- +/// @name Functions +///---------------- + +/** + Returns a Boolean value that indicates whether the given objects are equal. + + The actual method of comparison is dependendent upon the class of the objects given. For example, given two `NSString` objects equality would be tested using `isEqualToString:`. + + @param object The first object to compare. + @param anotherObject The second object to compare. + @return `YES` if the objects are equal, otherwise `NO`. + */ +BOOL RKObjectIsEqualToObject(id object, id anotherObject); + +/** + Returns a Boolean value that indicates if the given class is a collection. + + The following classes are considered collections: + + 1. `NSSet` + 1. `NSArray` + 1. `NSOrderedSet` + + `NSDictionary` objects are **not** considered collections as they are typically object representations. + + @param aClass The class to check. + @return `YES` if the given class is a collection. + */ +BOOL RKClassIsCollection(Class aClass); + +/** + Returns a Boolean value that indicates if the given object is a collection. + + Implemented by invoking `RKClassIsCollection` with the class of the given object. + @param object The object to be tested. + @return `YES` if the given object is a collection, else `NO`. + @see `RKClassIsCollection` + */ +BOOL RKObjectIsCollection(id object); + +/** + Returns a Boolean value that indicates if the given object is collection containing only instances of `NSManagedObject` or a class that inherits from `NSManagedObject`. + + @param object The object to be tested. + @return `YES` if the object is a collection containing only `NSManagedObject` derived objects. + */ +BOOL RKObjectIsCollectionContainingOnlyManagedObjects(id object); + +/** + Returns a Boolean value that indicates if the given object is a collection containing subcollections. + + @param object The object to be tested. + @return `YES` if the object is a collection of collections, else `NO`. + */ +BOOL RKObjectIsCollectionOfCollections(id object); + +/** + Returns an appropriate class to use for KVC access based on the Objective C runtime type encoding. + + Objective C Runtime type encodings: https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html + KVC Scalar/Structure support: http://developer.apple.com/library/ios/#documentation/cocoa/conceptual/KeyValueCoding/Articles/DataTypes.html#//apple_ref/doc/uid/20002171-BAJEAIEE + + @param type An Objective C Runtime type encoding + @return The class name for the property type encoded in the given attribute string, an appropriate class for wrapping/unwrapping the primitive type, or `Nil` when no transformation is required or possible. + */ +Class RKKeyValueCodingClassForObjCType(const char *type); + +/** + Returns an appropriate class to use for KVC access based on the output obtained via the `property_getAttributes` reflection API. + + @param attr A c string containing encoding attribute information. + @return The class name for the property type encoded in the given attribute string, an appropriate class for wrapping/unwrapping the primitive type, or `Nil` when no transformation is required or possible. + */ +Class RKKeyValueCodingClassFromPropertyAttributes(const char *attr); + +/** + Returns the name of a property when provided the name of a property obtained via the `property_getAttributes` reflection API. + + @param attributeString A string object encoding attribute information. + @return The class name for the property type encoded in the given attribute string or `@"NULL"` if the property does not have an object type (the declared property is for a primitive type). + */ +NSString *RKPropertyTypeFromAttributeString(NSString *attributeString); + +#ifdef __cplusplus +} +#endif diff --git a/Pods/RestKit/Code/ObjectMapping/RKObjectUtilities.m b/Pods/RestKit/Code/ObjectMapping/RKObjectUtilities.m new file mode 100644 index 0000000..052335e --- /dev/null +++ b/Pods/RestKit/Code/ObjectMapping/RKObjectUtilities.m @@ -0,0 +1,148 @@ +// +// RKObjectUtilities.m +// RestKit +// +// Created by Blake Watters on 9/30/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import <objc/message.h> +#import <objc/runtime.h> +#import "RKObjectUtilities.h" + +BOOL RKObjectIsEqualToObject(id object, id anotherObject) { + NSCAssert(object, @"Expected object not to be nil"); + NSCAssert(anotherObject, @"Expected anotherObject not to be nil"); + + return (object == anotherObject) || [object isEqual:anotherObject]; +} + +BOOL RKClassIsCollection(Class aClass) +{ + return (aClass && ([aClass isSubclassOfClass:[NSSet class]] || + [aClass isSubclassOfClass:[NSArray class]] || + [aClass isSubclassOfClass:[NSOrderedSet class]])); +} + +BOOL RKObjectIsCollection(id object) +{ + return RKClassIsCollection([object class]); +} + +BOOL RKObjectIsCollectionContainingOnlyManagedObjects(id object) +{ + if (! RKObjectIsCollection(object)) return NO; + Class managedObjectClass = NSClassFromString(@"NSManagedObject"); + if (! managedObjectClass) return NO; + for (id instance in object) { + if (! [instance isKindOfClass:managedObjectClass]) return NO; + } + return YES; +} + +BOOL RKObjectIsCollectionOfCollections(id object) +{ + if (! RKObjectIsCollection(object)) return NO; + id collectionSanityCheckObject = nil; + if ([object respondsToSelector:@selector(anyObject)]) collectionSanityCheckObject = [object anyObject]; + if ([object respondsToSelector:@selector(lastObject)]) collectionSanityCheckObject = [object lastObject]; + return RKObjectIsCollection(collectionSanityCheckObject); +} + +Class RKKeyValueCodingClassForObjCType(const char *type) +{ + if (type) { + switch (type[0]) { + case _C_ID: { + char *openingQuoteLoc = strchr(type, '"'); + if (openingQuoteLoc) { + char *closingQuoteLoc = strchr(openingQuoteLoc+1, '"'); + if (closingQuoteLoc) { + size_t classNameStrLen = closingQuoteLoc-openingQuoteLoc; + char className[classNameStrLen]; + memcpy(className, openingQuoteLoc+1, classNameStrLen-1); + // Null-terminate the array to stringify + className[classNameStrLen-1] = '\0'; + return objc_getClass(className); + } + } + // If there is no quoted class type (id), it can be used as-is. + return Nil; + } + + case _C_CHR: // char + case _C_UCHR: // unsigned char + case _C_SHT: // short + case _C_USHT: // unsigned short + case _C_INT: // int + case _C_UINT: // unsigned int + case _C_LNG: // long + case _C_ULNG: // unsigned long + case _C_LNG_LNG: // long long + case _C_ULNG_LNG: // unsigned long long + case _C_FLT: // float + case _C_DBL: // double + return [NSNumber class]; + + case _C_BOOL: // C++ bool or C99 _Bool + return objc_getClass("NSCFBoolean") + ?: objc_getClass("__NSCFBoolean") + ?: [NSNumber class]; + + case _C_STRUCT_B: // struct + case _C_BFLD: // bitfield + case _C_UNION_B: // union + return [NSValue class]; + + case _C_ARY_B: // c array + case _C_PTR: // pointer + case _C_VOID: // void + case _C_CHARPTR: // char * + case _C_CLASS: // Class + case _C_SEL: // selector + case _C_UNDEF: // unknown type (function pointer, etc) + default: + break; + } + } + return Nil; +} + +Class RKKeyValueCodingClassFromPropertyAttributes(const char *attr) +{ + if (attr) { + const char *typeIdentifierLoc = strchr(attr, 'T'); + if (typeIdentifierLoc) { + return RKKeyValueCodingClassForObjCType(typeIdentifierLoc+1); + } + } + return Nil; +} + +NSString *RKPropertyTypeFromAttributeString(NSString *attributeString) +{ + NSString *type = [NSString string]; + NSScanner *typeScanner = [NSScanner scannerWithString:attributeString]; + [typeScanner scanUpToCharactersFromSet:[NSCharacterSet characterSetWithCharactersInString:@"@"] intoString:NULL]; + + // we are not dealing with an object + if ([typeScanner isAtEnd]) { + return @"NULL"; + } + [typeScanner scanCharactersFromSet:[NSCharacterSet characterSetWithCharactersInString:@"\"@"] intoString:NULL]; + // this gets the actual object type + [typeScanner scanUpToCharactersFromSet:[NSCharacterSet characterSetWithCharactersInString:@"\""] intoString:&type]; + return type; +} diff --git a/Pods/RestKit/Code/ObjectMapping/RKPropertyInspector.h b/Pods/RestKit/Code/ObjectMapping/RKPropertyInspector.h new file mode 100644 index 0000000..98b5d07 --- /dev/null +++ b/Pods/RestKit/Code/ObjectMapping/RKPropertyInspector.h @@ -0,0 +1,117 @@ +// +// RKPropertyInspector.h +// RestKit +// +// Created by Blake Watters on 3/4/10. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import <Foundation/Foundation.h> + +@class NSEntityDescription; + +/** + * The object used to store attributes for each property; used as the value in the class dictionary. + */ +@interface RKPropertyInspectorPropertyInfo : NSObject + +/** + Creates a new RKPropertyInspectorPropertyInfo instance with the given information + */ ++ (instancetype)propertyInfoWithName:(NSString *)name keyValueClass:(Class)kvClass isPrimitive:(BOOL)isPrimitive; + +/** + The name of the property + */ +@property (nonatomic, copy, readonly) NSString *name; + +/** + The class used for key-value coding access to the property. + + If the property is an object type, then the class set for this key will be the type of the property. If the property is a primitive, then the class set for the key will be the boxed type used for KVC access to the property. For example, an `NSInteger` property is boxed to an `NSNumber` for KVC purposes. + */ +@property (nonatomic, strong, readonly) Class keyValueCodingClass; + +/** + A BOOL value that indicates if the property is a primitive (non-object) value. + */ +@property (nonatomic, readonly) BOOL isPrimitive; + +@end + + +/** + The `RKPropertyInspector` class provides an interface for introspecting the properties and attributes of classes using the reflection capabilities of the Objective-C runtime. Once inspected, the properties inspection details are cached. + */ +@interface RKPropertyInspector : NSObject + +///----------------------------------------------- +/// @name Retrieving the Shared Inspector Instance +///----------------------------------------------- + +/** + Returns the shared property inspector singleton instance. + + @return The shared `RKPropertyInspector` instance. + */ ++ (RKPropertyInspector *)sharedInspector; + +///------------------------------------------------------ +/// @name Retrieving the Properties and Types for a Class +///------------------------------------------------------ + +/** + Returns a dictionary keyed by property name that includes the key-value coding class of the property and a Boolean indicating if the property is backed by a primitive (non-object) value. The RKPropertyInspectorPropertyInfo object for each property includes details about the key-value coding class representing the property and if the property is backed by a primitive type. + + @param objectClass The class to inspect the properties of. + @return A dictionary keyed by property name that includes details about all declared properties of the class. + */ +- (NSDictionary *)propertyInspectionForClass:(Class)objectClass; + +/** + Returns the `Class` object specifying the type of the property with given name on a class. + + @param propertyName The name of the property to retrieve the type of. + @param objectClass The class to retrieve the property from. + @param isPrimitive A pointer to a Boolean value to set indicating if the specified property is of a primitive (non-object) type. + @return A `Class` object specifying the type of the requested property. + */ +- (Class)classForPropertyNamed:(NSString *)propertyName ofClass:(Class)objectClass isPrimitive:(BOOL *)isPrimitive; + +@end + +///---------------------------- +/// @name Convenience Functions +///---------------------------- + +/** + Returns the class of the attribute or relationship property at the key path of the given object. + + Given a key path to a string property, this will return an `NSString`, etc. + + @param keyPath The key path to the property to retrieve the class of. + @param object The object to evaluate. + @return The class of the property at the given key path. + */ +Class RKPropertyInspectorGetClassForPropertyAtKeyPathOfObject(NSString *keyPath, id object); + +/** + Returns a Boolean value indicating if the property at the specified key path for a given object is modeled by a primitive type. + + @param keyPath The key path to inspect the property of. + @param object The object to evaluate. + @return `YES` if the property is a primitive, else `NO`. + */ +BOOL RKPropertyInspectorIsPropertyAtKeyPathOfObjectPrimitive(NSString *keyPath, id object); diff --git a/Pods/RestKit/Code/ObjectMapping/RKPropertyInspector.m b/Pods/RestKit/Code/ObjectMapping/RKPropertyInspector.m new file mode 100644 index 0000000..7106713 --- /dev/null +++ b/Pods/RestKit/Code/ObjectMapping/RKPropertyInspector.m @@ -0,0 +1,207 @@ +// +// RKPropertyInspector.m +// RestKit +// +// Created by Blake Watters on 3/4/10. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import <objc/runtime.h> +#import "RKPropertyInspector.h" +#import "RKLog.h" +#import "RKObjectUtilities.h" + +// Set Logging Component +#undef RKLogComponent +#define RKLogComponent RKlcl_cRestKitObjectMapping + +NSString * const RKPropertyInspectionNameKey = @"name"; +NSString * const RKPropertyInspectionKeyValueCodingClassKey = @"keyValueCodingClass"; +NSString * const RKPropertyInspectionIsPrimitiveKey = @"isPrimitive"; + + +@implementation RKPropertyInspectorPropertyInfo + ++ (instancetype)propertyInfoWithName:(NSString *)name keyValueClass:(Class)kvClass isPrimitive:(BOOL)isPrimitive +{ + return [[self alloc] initWithName:name keyValueClass:kvClass isPrimitive:isPrimitive]; +} + +- (instancetype)initWithName:(NSString *)name keyValueClass:(Class)kvClass isPrimitive:(BOOL)isPrimitive +{ + if (self = [super init]) { + _name = [name copy]; + _keyValueCodingClass = kvClass; + _isPrimitive = isPrimitive; + } + return self; +} + +@end + + +@interface RKPropertyInspector () +#if OS_OBJECT_USE_OBJC +@property (nonatomic, strong) dispatch_queue_t queue; +#else +@property (nonatomic, assign) dispatch_queue_t queue; +#endif +@property (nonatomic, strong) NSMutableDictionary *inspectionCache; +@end + +@implementation RKPropertyInspector + ++ (RKPropertyInspector *)sharedInspector +{ + static RKPropertyInspector *sharedInspector = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedInspector = [RKPropertyInspector new]; + }); + + return sharedInspector; +} + +- (instancetype)init +{ + self = [super init]; + if (self) { + // NOTE: We use an `NSMutableDictionary` because it is *much* faster than `NSCache` on lookup + self.inspectionCache = [NSMutableDictionary dictionary]; + self.queue = dispatch_queue_create("org.restkit.core-data.property-inspection-queue", DISPATCH_QUEUE_CONCURRENT); + } + + return self; +} + +- (void)dealloc +{ +#if !OS_OBJECT_USE_OBJC + if (_queue) dispatch_release(_queue); +#endif + _queue = NULL; +} + +- (NSDictionary *)propertyInspectionForClass:(Class)objectClass +{ + __block NSMutableDictionary *inspection; + dispatch_sync(self.queue, ^{ + inspection = (self.inspectionCache)[objectClass]; + }); + if (inspection) return inspection; + + inspection = [NSMutableDictionary dictionary]; + + //include superclass properties + Class currentClass = objectClass; + while (currentClass != nil) { + // Get the raw list of properties + unsigned int outCount = 0; + objc_property_t *propList = class_copyPropertyList(currentClass, &outCount); + + // Collect the property names + for (typeof(outCount) i = 0; i < outCount; i++) { + objc_property_t *prop = propList + i; + const char *propName = property_getName(*prop); + + if (strcmp(propName, "_mapkit_hasPanoramaID") != 0) { + const char *attr = property_getAttributes(*prop); + if (attr) { + Class aClass = RKKeyValueCodingClassFromPropertyAttributes(attr); + if (aClass) { + NSString *propNameString = [[NSString alloc] initWithCString:propName encoding:NSUTF8StringEncoding]; + if (propNameString) { + BOOL isPrimitive = NO; + if (attr) { + const char *typeIdentifierLoc = strchr(attr, 'T'); + if (typeIdentifierLoc) { + isPrimitive = (typeIdentifierLoc[1] != '@'); + } + } + + RKPropertyInspectorPropertyInfo *info; + info = [RKPropertyInspectorPropertyInfo propertyInfoWithName:propNameString + keyValueClass:aClass + isPrimitive:isPrimitive]; + inspection[propNameString] = info; + } + } + } + } + } + + free(propList); + Class superclass = [currentClass superclass]; + Class nsManagedObject = NSClassFromString(@"NSManagedObject"); + currentClass = (superclass == [NSObject class] || (nsManagedObject && superclass == nsManagedObject)) ? nil : superclass; + } + + /* dispatch_barrier_async is dangerous if we are called from +initialize */ + dispatch_barrier_sync(self.queue, ^{ + (self.inspectionCache)[(id<NSCopying>)objectClass] = inspection; + RKLogDebug(@"Cached property inspection for Class '%@': %@", NSStringFromClass(objectClass), inspection); + }); + return inspection; +} + +- (Class)classForPropertyNamed:(NSString *)propertyName ofClass:(Class)objectClass isPrimitive:(BOOL *)isPrimitive +{ + NSDictionary *classInspection = [self propertyInspectionForClass:objectClass]; + RKPropertyInspectorPropertyInfo *propertyInspection = classInspection[propertyName]; + if (isPrimitive) *isPrimitive = propertyInspection.isPrimitive; + return propertyInspection.keyValueCodingClass; +} + +@end + + +@interface NSObject (RKPropertyInspection) +- (Class)rk_classForPropertyAtKeyPath:(NSString *)keyPath isPrimitive:(BOOL *)isPrimitive; +@end + +@implementation NSObject (RKPropertyInspection) + +- (Class)rk_classForPropertyAtKeyPath:(NSString *)keyPath isPrimitive:(BOOL *)isPrimitive +{ + NSRange dotRange = [keyPath rangeOfString:@"." options:NSLiteralSearch]; + RKPropertyInspector *inspector = [RKPropertyInspector sharedInspector]; + Class propertyClass = [self class]; + + if (dotRange.length == 0) { + return [inspector classForPropertyNamed:keyPath ofClass:propertyClass isPrimitive:isPrimitive]; + } + + NSArray *components = [keyPath componentsSeparatedByString:@"."]; + for (NSString *property in components) { + propertyClass = [inspector classForPropertyNamed:property ofClass:propertyClass isPrimitive:isPrimitive]; + if (! propertyClass) break; + } + + return propertyClass; +} + +@end + +Class RKPropertyInspectorGetClassForPropertyAtKeyPathOfObject(NSString *keyPath, id object) +{ + return [object rk_classForPropertyAtKeyPath:keyPath isPrimitive:nil]; +} + +BOOL RKPropertyInspectorIsPropertyAtKeyPathOfObjectPrimitive(NSString *keyPath, id object) +{ + BOOL isPrimitive = NO; + [object rk_classForPropertyAtKeyPath:keyPath isPrimitive:&isPrimitive]; + return isPrimitive; +} diff --git a/Pods/RestKit/Code/ObjectMapping/RKPropertyMapping.h b/Pods/RestKit/Code/ObjectMapping/RKPropertyMapping.h new file mode 100644 index 0000000..5f39859 --- /dev/null +++ b/Pods/RestKit/Code/ObjectMapping/RKPropertyMapping.h @@ -0,0 +1,84 @@ +// +// RKPropertyMapping.h +// RestKit +// +// Created by Blake Watters on 8/27/12. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import <Foundation/Foundation.h> + +@class RKObjectMapping; +@protocol RKValueTransforming; + +/** + `RKPropertyMapping` is an abstract class for describing the properties being mapped within an `RKObjectMapping` or `RKEntityMapping` object. It defines the common interface for its concrete subclasses `RKAttributeMapping` and `RKRelationshipMapping`. Each property mapping defines a single transformation from a source key path (often in the deserialized representation of a JSON or XML document) to a destination key path (typically on a target object). + */ +@interface RKPropertyMapping : NSObject <NSCopying> + +///------------------------------------------ +/// @name Accessing the Parent Object Mapping +///------------------------------------------ + +/** + Returns the object mapping the receiver is added to. + */ +@property (nonatomic, weak, readonly) RKObjectMapping *objectMapping; + +///----------------------------------------------------- +/// @name Accessing the Source and Destination Key Paths +///----------------------------------------------------- + +/** + A key path on the source object from which to get information that is to be mapped onto the destination object. + */ +@property (nonatomic, copy, readonly) NSString *sourceKeyPath; + +/** + A key path on the destination object on which to set information that has been mapped from the source object. + */ +@property (nonatomic, copy, readonly) NSString *destinationKeyPath; + +///------------------------------------- +/// @name Specifying a Value Transformer +///------------------------------------- + +/** + Specifies the class used to represent the value of the mapped property. A value of `Nil` (which is the default value) indicates the property class is to be determined by runtime introspection. + + In cases where run-time type introspection cannot be performed (such as during object parameterization) you can specify the class used to represent the value of the property being mapped. + */ +@property (nonatomic, strong) Class propertyValueClass; + +/** + A value transformer with which to process input values being mapped with the receiver. If `nil`, then the `valueTransformer` of the parent `objectMapping` will be used instead. + */ +@property (nonatomic, strong) id<RKValueTransforming> valueTransformer; + +///---------------------------------- +/// @name Comparing Property Mappings +///---------------------------------- + +/** + Compares the receiving property mapping to another property mapping. + + Two property mappings are equal if they are of the same type (i.e. an `RKAttributeMapping` or an `RKRelatiobshipMapping` object) and specify a mapping from the same source key path to the same destination key path. + + @param otherMapping The property mapping object with which to compare the receiver. + @return `YES` if `otherMapping` specifies the same mapping as the receiver, otherwise `NO`. + */ +- (BOOL)isEqualToMapping:(RKPropertyMapping *)otherMapping; + +@end diff --git a/Pods/RestKit/Code/ObjectMapping/RKPropertyMapping.m b/Pods/RestKit/Code/ObjectMapping/RKPropertyMapping.m new file mode 100644 index 0000000..0fc2ca1 --- /dev/null +++ b/Pods/RestKit/Code/ObjectMapping/RKPropertyMapping.m @@ -0,0 +1,79 @@ +// +// RKPropertyMapping.m +// RestKit +// +// Created by Blake Watters on 8/27/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKPropertyMapping.h" +#import "RKObjectMapping.h" + +/** + For consistency with URI Templates (and most web templating languages in general) we are transitioning + to using braces "{}" instead of parentheses "()" for denoting the variables in the key paths. + */ +static NSString *RKStringByReplacingUnderscoresWithBraces(NSString *string) +{ + return [[string stringByReplacingOccurrencesOfString:@"(" withString:@"{"] stringByReplacingOccurrencesOfString:@")" withString:@"}"]; +} + +@interface RKPropertyMapping () +// Synthesize as read/write to allow assignment in `RKObjectMapping` +@property (nonatomic, weak, readwrite) RKObjectMapping *objectMapping; +@property (nonatomic, copy, readwrite) NSString *sourceKeyPath; +@property (nonatomic, copy, readwrite) NSString *destinationKeyPath; +@end + +@implementation RKPropertyMapping + +- (id)copyWithZone:(NSZone *)zone +{ + RKPropertyMapping *copy = [[[self class] allocWithZone:zone] init]; + copy.sourceKeyPath = self.sourceKeyPath; + copy.destinationKeyPath = self.destinationKeyPath; + copy.propertyValueClass = self.propertyValueClass; + copy.valueTransformer = self.valueTransformer; + return copy; +} + +- (BOOL)isEqualToMapping:(RKPropertyMapping *)otherMapping +{ + return [otherMapping isMemberOfClass:[self class]] && + (self.sourceKeyPath == otherMapping.sourceKeyPath || [self.sourceKeyPath isEqual:otherMapping.sourceKeyPath]) && + [self.destinationKeyPath isEqual:otherMapping.destinationKeyPath]; +} + +- (void)setSourceKeyPath:(NSString *)sourceKeyPath +{ + _sourceKeyPath = RKStringByReplacingUnderscoresWithBraces(sourceKeyPath); +} + +- (void)setDestinationKeyPath:(NSString *)destinationKeyPath +{ + _destinationKeyPath = RKStringByReplacingUnderscoresWithBraces(destinationKeyPath); +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@"<%@: %p %@ => %@>", self.class, self, self.sourceKeyPath, self.destinationKeyPath]; +} + +- (id<RKValueTransforming>)valueTransformer +{ + return _valueTransformer ?: [self.objectMapping valueTransformer]; +} + +@end diff --git a/Pods/RestKit/Code/ObjectMapping/RKRelationshipMapping.h b/Pods/RestKit/Code/ObjectMapping/RKRelationshipMapping.h new file mode 100644 index 0000000..5c81276 --- /dev/null +++ b/Pods/RestKit/Code/ObjectMapping/RKRelationshipMapping.h @@ -0,0 +1,95 @@ +// +// RKRelationshipMapping.h +// RestKit +// +// Created by Blake Watters on 5/4/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKPropertyMapping.h" + +@class RKMapping; + +typedef NS_ENUM(NSInteger, RKAssignmentPolicy) { + RKAssignmentPolicySet, // Set the relationship to the new value and leave the existing objects alone, breaking the relationship to existing objects at the destination. This is the default policy for `RKRelationshipMapping`. + RKAssignmentPolicyReplace, // Set the relationship to the new value and destroy the previous value, replacing the existing objects at the destination of the relationship. + RKAssignmentPolicyUnion, // Set the relationship to the union of the existing value and the new value being assigned. Only applicable for to-many relationships. + + // Deprecated + RKSetAssignmentPolicy = RKAssignmentPolicySet, // Will be deprecated, use `RKAssignmentPolicySet` instead + RKReplaceAssignmentPolicy = RKAssignmentPolicyReplace, // Will be deprecated, use `RKAssignmentPolicyReplace` instead + RKUnionAssignmentPolicy = RKAssignmentPolicyUnion, // Will be deprecated, use `RKAssignmentPolicyUnion` instead +} ; + +/** + The `RKRelationshipMapping` class is used to describe relationships of a class in an `RKObjectMapping` or an entity in an `RKEntityMapping` object. + + `RKRelationshipMapping` extends `RKPropertyMapping` to describe features specific to relationships, including the `RKMapping` object describing how to map the destination object. + + Relationship mappings are described in terms of a source key path, which identifies a key in the parent object representation under which the data for the relationship is nested, and a destination key path, which specifies the key path at which the mapped object is to be assigned on the parent entity. The key paths of the property mappings of the `RKMapping` object in the relationship mapping are evaluated against the nested object representationship at the source key path. + + ## Mapping a Non-nested Relationship from the Parent Representation + + It can often be desirable to map data for a relationship directly from the parent object representation, rather than under a nested key path. When a relationship mapping is constructed with a `nil` value for the source key path, then the `RKMapping` object is evaluated against the parent representation. + + ## Assignment Policy + + When mapping a relationship, the typical desired behavior is to set the destination of the relationship to the newly mapped values from the object representation being processed. There are times in which it is desirable to use different assignment behaviors. The way in which the relationship is assigned can be controlled by the assignmentPolicy property. There are currently three distinct assignment policies available: + + 1. `RKSetAssignmentPolicy` - Instructs the mapper to assign the new destination value to the relationship directly. No further action is taken and the relationship to the old objects is broken. This is the default assignment policy. + 1. `RKReplaceAssignmentPolicy` - Instructs the mapper to assign the new destination value to the relationship and delete any existing object or objects at the destination. The deletion behavior is contextual based on the type of objects being mapped (i.e. Core Data vs NSObject) and is delegated to the mapping operation data source. + 1. `RKUnionAssignmentPolicy` - Instructs the mapper to build a new value for the relationship by unioning the existing value with the new value and set the combined value to the relationship. The union assignment policy is only appropriate for use with a to-many relationship. + + */ +@interface RKRelationshipMapping : RKPropertyMapping + +///-------------------------------------- +/// @name Creating a Relationship Mapping +///-------------------------------------- + +/** + Creates and returns a new relationship mapping object describing how to transform a related object representation at `sourceKeyPath` to a new representation at `destinationKeyPath` using the given mapping. + + The mapping may describe a to-one or a to-many relationship. The appropriate handling of the source representation is deferred until run-time and is determined by performing reflection on the data retrieved from the source object representation by sending a `valueForKeyPath:` message where the key path is the value given in `sourceKeyPath`. If an `NSArray`, `NSSet` or `NSOrderedSet` object is returned, the related object representation is processed as a to-many collection. Otherwise the representation is considered to be a to-one. + + @param sourceKeyPath A key path from which to retrieve data in the source object representation that is to be mapped as a relationship. If `nil`, then the mapping is performed directly against the parent object representation. + @param destinationKeyPath The key path on the destination object to set the object mapped results. + @param mapping A mapping object describing how to map the data retrieved from `sourceKeyPath` that is to be set on `destinationKeyPath`. + */ ++ (instancetype)relationshipMappingFromKeyPath:(NSString *)sourceKeyPath toKeyPath:(NSString *)destinationKeyPath withMapping:(RKMapping *)mapping; + +///---------------------------------------- +/// @name Accessing the Destination Mapping +///---------------------------------------- + +/** + An `RKMapping` object describing how to map the object representation at `sourceKeyPath` to a new represenation at `destinationKeyPath`. + */ +@property (nonatomic, strong, readonly) RKMapping *mapping; + +///---------------------------------------- +/// @name Configuring the Assignment Policy +///---------------------------------------- + +/** + The assignment policy to use when applying the relationship mapping. + + The assignment policy determines how a relationship is set when there are existing objects at the destination of the relationship. The existing values can be disconnected from the parent and left in the graph (`RKSetAssignmentPolicy`), deleted and replaced by the new value (`RKReplaceAssignmentPolicy`), or the new value can be unioned with the existing objects to create a new combined value (`RKUnionAssignmentPolicy`). + + **Default**: `RKSetAssignmentPolicy` + */ +@property (nonatomic, assign) RKAssignmentPolicy assignmentPolicy; + +@end diff --git a/Pods/RestKit/Code/ObjectMapping/RKRelationshipMapping.m b/Pods/RestKit/Code/ObjectMapping/RKRelationshipMapping.m new file mode 100644 index 0000000..ae867c0 --- /dev/null +++ b/Pods/RestKit/Code/ObjectMapping/RKRelationshipMapping.m @@ -0,0 +1,70 @@ +// +// RKRelationshipMapping.m +// RestKit +// +// Created by Blake Watters on 5/4/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKRelationshipMapping.h" +#import "RKMapping.h" + +@interface RKPropertyMapping () +@property (nonatomic, copy, readwrite) NSString *sourceKeyPath; +@property (nonatomic, copy, readwrite) NSString *destinationKeyPath; +@end + +@interface RKRelationshipMapping () +@property (nonatomic, strong, readwrite) RKMapping *mapping; +@end + +@implementation RKRelationshipMapping + ++ (instancetype)relationshipMappingFromKeyPath:(NSString *)sourceKeyPath toKeyPath:(NSString *)destinationKeyPath withMapping:(RKMapping *)mapping +{ + RKRelationshipMapping *relationshipMapping = [self new]; + relationshipMapping.sourceKeyPath = sourceKeyPath; + relationshipMapping.destinationKeyPath = destinationKeyPath; + relationshipMapping.mapping = mapping; + return relationshipMapping; +} + +- (instancetype)init +{ + self = [super init]; + if (self) { + self.assignmentPolicy = RKSetAssignmentPolicy; + } + return self; +} + +- (id)copyWithZone:(NSZone *)zone +{ + RKRelationshipMapping *copy = [super copyWithZone:zone]; + copy.mapping = self.mapping; + copy.assignmentPolicy = self.assignmentPolicy; + return copy; +} + +- (BOOL)isEqualToMapping:(RKRelationshipMapping *)otherMapping +{ + if (! [otherMapping isMemberOfClass:[RKRelationshipMapping class]]) return NO; + if (! [super isEqualToMapping:otherMapping]) return NO; + if (self.mapping == nil && otherMapping.mapping == nil) return YES; + + return [self.mapping isEqualToMapping:otherMapping.mapping]; +} + +@end diff --git a/Pods/RestKit/Code/RestKit.h b/Pods/RestKit/Code/RestKit.h new file mode 100644 index 0000000..30e1951 --- /dev/null +++ b/Pods/RestKit/Code/RestKit.h @@ -0,0 +1,50 @@ +// +// RestKit.h +// RestKit +// +// Created by Blake Watters on 2/19/10. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#ifndef _RESTKIT_ +#define _RESTKIT_ + +#if __has_include("ObjectMapping.h") +#import "ObjectMapping.h" +#endif + +#if __has_include("Network.h") +#import "Network.h" +#endif + +#if __has_include("Support.h") +#import "Support.h" +#endif + +#if __has_include("RKCoreData.h") +#import "RKCoreData.h" +#endif + +/** + Set the App logging component. This header + file is generally only imported by apps that + are pulling in all of RestKit. By setting the + log component to App here, we allow the app developer + to use RKLog() in their own app. + */ +#undef RKLogComponent +#define RKLogComponent RKlcl_cApp + +#endif /* _RESTKIT_ */ diff --git a/Pods/RestKit/Code/Support.h b/Pods/RestKit/Code/Support.h new file mode 100644 index 0000000..ba3e127 --- /dev/null +++ b/Pods/RestKit/Code/Support.h @@ -0,0 +1,31 @@ +// +// Support.h +// RestKit +// +// Created by Blake Watters on 9/30/10. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Load shared support code +#import "RKErrors.h" +#import "RKMIMETypes.h" +#import "RKLog.h" +#import "RKDotNetDateFormatter.h" +#import "RKPathUtilities.h" +#import "RKDictionaryUtilities.h" +#import "RKURLEncodedSerialization.h" +#import "RKNSJSONSerialization.h" +#import "RKMIMETypeSerialization.h" +#import "RKStringTokenizer.h" diff --git a/Pods/RestKit/Code/Support/RKDictionaryUtilities.h b/Pods/RestKit/Code/Support/RKDictionaryUtilities.h new file mode 100644 index 0000000..1752c3b --- /dev/null +++ b/Pods/RestKit/Code/Support/RKDictionaryUtilities.h @@ -0,0 +1,46 @@ +// +// RKDictionaryUtilities.h +// RestKit +// +// Created by Blake Watters on 9/11/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#ifdef __cplusplus +extern "C" { +#endif + +#import <Foundation/Foundation.h> + +/** + Reverse merges two dictionary to produce a new dictionary wherein the keys in the second dictionary have taken precedence in instances where keys overlap. The merge is performed recursively such that subdictionaries are reverse merged as well. + + @param dict1 The dictionary to be reverse merged. + @param dict2 A secondary dictionary to perform the reverse merging with. + @return A new `NSDicionary` object that is the product of the reverse merge. + */ +NSDictionary *RKDictionaryByMergingDictionaryWithDictionary(NSDictionary *dict1, NSDictionary *dict2); + +/** + Return a new dictionary by stripping out any percent escapes (such as %20) from the given dictionary's key and values. + + @param dictionary The dictionary from which to remove the percent escape sequences. + @return A new `NSDictionary` wherein any percent escape sequences in the key and values have been replaced with their literal values. + */ +NSDictionary *RKDictionaryByReplacingPercentEscapesInEntriesFromDictionary(NSDictionary *dictionary); + +#ifdef __cplusplus +} +#endif diff --git a/Pods/RestKit/Code/Support/RKDictionaryUtilities.m b/Pods/RestKit/Code/Support/RKDictionaryUtilities.m new file mode 100644 index 0000000..66b09ce --- /dev/null +++ b/Pods/RestKit/Code/Support/RKDictionaryUtilities.m @@ -0,0 +1,44 @@ +// +// RKDictionaryUtilities.m +// RestKit +// +// Created by Blake Watters on 9/11/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// + +#import "RKDictionaryUtilities.h" + +NSDictionary *RKDictionaryByMergingDictionaryWithDictionary(NSDictionary *dict1, NSDictionary *dict2) +{ + if (! dict1) return dict2; + if (! dict2) return dict1; + + NSMutableDictionary *mergedDictionary = [dict1 mutableCopy]; + + for (id key2 in dict2) { + id obj2 = dict2[key2]; + id obj1 = dict1[key2]; + if ([obj1 isKindOfClass:[NSDictionary class]] && [obj2 isKindOfClass:[NSDictionary class]]) { + NSDictionary *mergedSubdict = RKDictionaryByMergingDictionaryWithDictionary(obj1, obj2); + mergedDictionary[key2] = mergedSubdict; + } else { + mergedDictionary[key2] = obj2; + } + } + + return mergedDictionary; +} + +NSDictionary *RKDictionaryByReplacingPercentEscapesInEntriesFromDictionary(NSDictionary *dictionary) +{ + NSMutableDictionary *results = [NSMutableDictionary dictionaryWithCapacity:[dictionary count]]; + [dictionary enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL *stop) + { + NSString *escapedKey = [key stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; + id escapedValue = value; + if ([value respondsToSelector:@selector(stringByReplacingPercentEscapesUsingEncoding:)]) + escapedValue = [value stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; + results[escapedKey] = escapedValue; + }]; + return results; +} diff --git a/Pods/RestKit/Code/Support/RKDotNetDateFormatter.h b/Pods/RestKit/Code/Support/RKDotNetDateFormatter.h new file mode 100644 index 0000000..03bc2b4 --- /dev/null +++ b/Pods/RestKit/Code/Support/RKDotNetDateFormatter.h @@ -0,0 +1,73 @@ +// +// RKDotNetDateFormatter.h +// RestKit +// +// Created by Greg Combs on 9/8/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import <Foundation/Foundation.h> + +/** + A subclass of `NSDateFormatter` that serves as translator between ASP.NET date serializations in JSON strings and NSDate objects. This is useful for properly mapping these dates from an ASP.NET driven backend. + + @warning DO NOT attempt to use `setDateFormat:` on this class. It will return invalid results. + */ +@interface RKDotNetDateFormatter : NSDateFormatter + +/** + Instantiates an autoreleased `RKDotNetDateFormatter` object with the timezone set to the given value. The default time zone is UTC. + + The supplied timeZone, such as one produced with `[NSTimeZone timeZoneWithName:@"UTC"]`, + is only used during calls to `stringFromDate:, for a detailed explanation see `dateFromString:` + + @param timeZone An NSTimeZone object. A `nil` value sets the timezone to the default value of UTC. + @return An autoreleased `RKDotNetDateFormatter` object + @see dotNetDateFormatter + */ ++ (instancetype)dotNetDateFormatterWithTimeZone:(NSTimeZone *)timeZone; + +/** + Returns an `NSDate` object from an ASP.NET style date string respresentation, as seen in JSON. + + Acceptable examples are: + /Date(1112715000000-0500)/ + /Date(1112715000000)/ + /Date(-1112715000000)/ + Where 1112715000000 is the number of milliseconds since January 1, 1970 00:00 GMT/UTC, and -0500 represents the timezone offset from GMT in 24-hour time. Negatives milliseconds are treated as dates before January 1, 1970. + + *NOTE* `NSDate` objects do not have timezones, and you should never change an actual date value based on a timezone offset. However, timezones are important when presenting dates to the user. Therefore, If an offset is present in the ASP.NET string (it should be), we actually ignore the offset portion because we want to store the actual date value in its raw form, without any pollution of timezone information. If, on the other hand, there is no offset in the ASP.NET string, we assume GMT (+0000) anyway. In summation, for this class `setTimeZone:` is ignored except when using `stringFromDate:` + + @param string The ASP.NET style string, /Date(1112715000000-0500)/ + @return An `NSDate` object. + @see `stringFromDate` + @see `NSDateFormatter` + @see `NSTimeZone` + */ +- (NSDate *)dateFromString:(NSString *)string; + +/** + Returns an ASP.NET style date string from an NSDate, such as /Date(1112715000000+0000)/ Where 1112715000000 is the number of milliseconds since January 1, 1970 00:00 GMT/UTC, and +0000 is the timezone offset from GMT in 24-hour time. + + *NOTE *GMT (+0000) is assumed otherwise specified via `setTimeZone:` + + @param date An `NSDate` object from which to return a string value. + @return The ASP.NET style string, /Date(1112715000000-0500)/ + @see `dateFromString` + @see `NSDateFormatter` + @see `NSTimeZone` + */ +- (NSString *)stringFromDate:(NSDate *)date; +@end diff --git a/Pods/RestKit/Code/Support/RKDotNetDateFormatter.m b/Pods/RestKit/Code/Support/RKDotNetDateFormatter.m new file mode 100644 index 0000000..11e2a53 --- /dev/null +++ b/Pods/RestKit/Code/Support/RKDotNetDateFormatter.m @@ -0,0 +1,115 @@ +// +// RKDotNetDateFormatter.h +// RestKit +// +// Created by Greg Combs on 9/8/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKDotNetDateFormatter.h" +#import "RKLog.h" + +static BOOL RKDotNetDateFormatterIsValidRange(NSRange rangeOfMatch) +{ + return (!NSEqualRanges(rangeOfMatch, NSMakeRange(NSNotFound, 0))); +} + +static NSTimeInterval RKDotNetDateFormatterSecondsFromMilliseconds(NSTimeInterval millisecs) +{ + return millisecs / 1000.f; +} + +static NSTimeInterval RKDotNetDateFormatterMillisecondsFromSeconds(NSTimeInterval seconds) +{ + return seconds *1000.f; +} + +@interface RKDotNetDateFormatter () +@property (nonatomic, strong) NSRegularExpression *dotNetExpression; + +- (NSString *)millisecondsFromString:(NSString *)string; +@end + +@implementation RKDotNetDateFormatter + ++ (instancetype)dotNetDateFormatterWithTimeZone:(NSTimeZone *)newTimeZone +{ + RKDotNetDateFormatter *formatter = [self new]; + if (newTimeZone) formatter.timeZone = newTimeZone; + return formatter; +} + +- (NSDate *)dateFromString:(NSString *)string +{ + NSString *milliseconds = [self millisecondsFromString:string]; + if (!milliseconds) { + RKLogError(@"Attempted to interpret an invalid .NET date string: %@", string); + return nil; + } + NSTimeInterval seconds = RKDotNetDateFormatterSecondsFromMilliseconds([milliseconds doubleValue]); + return [NSDate dateWithTimeIntervalSince1970:seconds]; +} + + +- (NSString *)stringFromDate:(NSDate *)date +{ + if (!date) { + RKLogError(@"Attempted to represent an invalid date: %@", date); + return nil; + } + return [self stringForObjectValue:date]; +} + +- (BOOL)getObjectValue:(id *)outValue forString:(NSString *)string errorDescription:(NSString **)error +{ + NSDate *date = [self dateFromString:string]; + if (outValue) + *outValue = date; + return (date != nil); +} + +- (NSString *)stringForObjectValue:(id)value +{ + NSParameterAssert([value isKindOfClass:[NSDate class]]); + NSString *timeZoneOffset = [super stringForObjectValue:value]; + NSTimeInterval milliseconds = RKDotNetDateFormatterMillisecondsFromSeconds([(NSDate *)value timeIntervalSince1970]); + return [NSString stringWithFormat:@"/Date(%1.0lf%@)/", milliseconds, timeZoneOffset]; +} + +- (instancetype)init +{ + self = [super init]; + if (self) { + self.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"]; + self.timeZone = [NSTimeZone timeZoneWithName:@"UTC"]; + [self setDateFormat:@"ZZ"]; // GMT offset, like "-0500" + NSString *pattern = @"\\/Date\\((-?\\d+)((?:[\\+\\-]\\d+)?)\\)\\/"; // /Date(mSecs)/ or /Date(-mSecs)/ or /Date(mSecs-0400)/ + self.dotNetExpression = [[NSRegularExpression alloc] initWithPattern:pattern options:NSRegularExpressionCaseInsensitive error:NULL]; + } + return self; +} + +- (NSString *)millisecondsFromString:(NSString *)string +{ + if (!string) return nil; + NSTextCheckingResult *match = [self.dotNetExpression firstMatchInString:string options:NSMatchingReportCompletion range:NSMakeRange(0, [string length])]; + if (!match) return nil; + NSRange millisecRange = [match rangeAtIndex:1]; + if (!RKDotNetDateFormatterIsValidRange(millisecRange)) return nil; + NSString *milliseconds = [string substringWithRange:millisecRange]; + return milliseconds; +} + +@end diff --git a/Pods/RestKit/Code/Support/RKErrors.h b/Pods/RestKit/Code/Support/RKErrors.h new file mode 100644 index 0000000..bf79280 --- /dev/null +++ b/Pods/RestKit/Code/Support/RKErrors.h @@ -0,0 +1,59 @@ +// +// RKErrors.h +// RestKit +// +// Created by Blake Watters on 3/25/10. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import <Foundation/Foundation.h> + +///--------------------------- +/// @name Error Domain & Codes +///--------------------------- + +// The error domain for RestKit generated errors +extern NSString * const RKErrorDomain; + +typedef NS_ENUM(NSInteger, RKRestKitError) { + RKUnsupportedMIMETypeError = 1, + RKOperationCancelledError = 2 +} ; + + +///-------------------------------------- +/// @name Error User Info Dictionary Keys +///-------------------------------------- + +/** + The key RestKit generated errors will appear at within an NSNotification + indicating an error + */ +extern NSString *const RKErrorNotificationErrorKey; + +/** + When RestKit constructs an NSError object from one or more RKErrorMessage + (or other object mapped error representations), the userInfo of the NSError + object will be populated with an array of the underlying error objects. + + These underlying errors can be accessed via RKObjectMapperErrorObjectsKey key. + + @see RKObjectMappingResult + */ +extern NSString *const RKObjectMapperErrorObjectsKey; + +extern NSString *const RKDetailedErrorsKey; // When multiple errors occur, they are stored in a composite error + +extern NSString *const RKMIMETypeErrorKey; diff --git a/Pods/RestKit/Code/Support/RKErrors.m b/Pods/RestKit/Code/Support/RKErrors.m new file mode 100644 index 0000000..ae9a154 --- /dev/null +++ b/Pods/RestKit/Code/Support/RKErrors.m @@ -0,0 +1,28 @@ +// +// RKErrors.m +// RestKit +// +// Created by Blake Watters on 3/25/10. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKErrors.h" + +NSString * const RKErrorDomain = @"org.restkit.RestKit.ErrorDomain"; + +NSString * const RKObjectMapperErrorObjectsKey = @"RKObjectMapperErrorObjectsKey"; +NSString * const RKErrorNotificationErrorKey = @"error"; +NSString * const RKDetailedErrorsKey = @"DetailedErrors"; +NSString * const RKMIMETypeErrorKey = @"MIME Type"; diff --git a/Pods/RestKit/Code/Support/RKLog.h b/Pods/RestKit/Code/Support/RKLog.h new file mode 100644 index 0000000..da5de94 --- /dev/null +++ b/Pods/RestKit/Code/Support/RKLog.h @@ -0,0 +1,248 @@ +// +// RKLog.h +// RestKit +// +// Created by Blake Watters on 5/3/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +/** + RestKit Logging is based on the LibComponentLogging framework + + @see lcl_config_components_RK.h + @see lcl_config_logger_RK.h + */ +#import "lcl_RK.h" + +/** + * Protocol which classes can implement to determine how RestKit log messages actually get handled. + * There is a single "current" logging class installed, which all log messages will flow + * through. + */ +@protocol RKLogging + ++ (void)logWithComponent:(_RKlcl_component_t)component + level:(_RKlcl_level_t)level + path:(const char *)file + line:(uint32_t)line + function:(const char *)function + format:(NSString *)format, ... NS_FORMAT_FUNCTION(6, 7); + +@end + +/** + * Functions to get and set the current RKLogging class. + */ +Class <RKLogging> RKGetLoggingClass(void); +void RKSetLoggingClass(Class <RKLogging> loggingClass); + + + +/** + RKLogComponent defines the active component within any given portion of RestKit + + By default, messages will log to the base 'RestKit' log component. All other components + used by RestKit are nested under this parent, so this effectively sets the default log + level for the entire library. + + The component can be undef'd and redefined to change the active logging component. + */ +#define RKLogComponent RKlcl_cRestKit + +/** + The logging macros. These macros will log to the currently active logging component + at the log level identified in the name of the macro. + + For example, in the `RKMappingOperation` class we would redefine the RKLogComponent: + + #undef RKLogComponent + #define RKLogComponent RKlcl_cRestKitObjectMapping + + The RKlcl_c prefix is the LibComponentLogging data structure identifying the logging component + we want to target within this portion of the codebase. See lcl_config_component_RK.h for reference. + + Having defined the logging component, invoking the logger via: + + RKLogInfo(@"This is my log message!"); + + Would result in a log message similar to: + + I RestKit.ObjectMapping:RKLog.h:42 This is my log message! + + The message will only be logged if the log level for the active component is equal to or higher + than the level the message was logged at (in this case, Info). + */ +#define RKLogCritical(...) \ +RKlcl_log(RKLogComponent, RKlcl_vCritical, @"" __VA_ARGS__) + +#define RKLogError(...) \ +RKlcl_log(RKLogComponent, RKlcl_vError, @"" __VA_ARGS__) + +#define RKLogWarning(...) \ +RKlcl_log(RKLogComponent, RKlcl_vWarning, @"" __VA_ARGS__) + +#define RKLogInfo(...) \ +RKlcl_log(RKLogComponent, RKlcl_vInfo, @"" __VA_ARGS__) + +#define RKLogDebug(...) \ +RKlcl_log(RKLogComponent, RKlcl_vDebug, @"" __VA_ARGS__) + +#define RKLogTrace(...) \ +RKlcl_log(RKLogComponent, RKlcl_vTrace, @"" __VA_ARGS__) + +/** + Log Level Aliases + + These aliases simply map the log levels defined within LibComponentLogger to something more friendly + */ +#define RKLogLevelOff RKlcl_vOff +#define RKLogLevelCritical RKlcl_vCritical +#define RKLogLevelError RKlcl_vError +#define RKLogLevelWarning RKlcl_vWarning +#define RKLogLevelInfo RKlcl_vInfo +#define RKLogLevelDebug RKlcl_vDebug +#define RKLogLevelTrace RKlcl_vTrace + +/** + Alias the LibComponentLogger logging configuration method. Also ensures logging + is initialized for the framework. + + Expects the name of the component and a log level. + + Examples: + + // Log debugging messages from the Network component + RKLogConfigureByName("RestKit/Network", RKLogLevelDebug); + + // Log only critical messages from the Object Mapping component + RKLogConfigureByName("RestKit/ObjectMapping", RKLogLevelCritical); + */ +#define RKLogConfigureByName(name, level) \ +RKlcl_configure_by_name(name, level); + +/** + Alias for configuring the LibComponentLogger logging component for the App. This + enables the end-user of RestKit to leverage RKLog() to log messages inside of + their apps. + */ +#define RKLogSetAppLoggingLevel(level) \ +RKlcl_configure_by_name("App", level); + +/** + Temporarily changes the logging level for the specified component and executes the block. Any logging + statements executed within the body of the block against the specified component will log at the new + logging level. After the block has executed, the logging level is restored to its previous state. + */ +#define RKLogToComponentWithLevelWhileExecutingBlock(_component, _level, _block) \ + do { \ + int _currentLevel = _RKlcl_component_level[_component]; \ + RKlcl_configure_by_component(_component, _level); \ + @try { \ + _block(); \ + } \ + @catch (NSException *exception) { \ + @throw; \ + } \ + @finally { \ + RKlcl_configure_by_component(_component, _currentLevel); \ + } \ + } while (false); + +/** + Temporarily turns off logging for the given logging component during execution of the block. + After the block has finished execution, the logging level is restored to its previous state. + */ +#define RKLogSilenceComponentWhileExecutingBlock(component, _block) \ + RKLogToComponentWithLevelWhileExecutingBlock(component, RKLogLevelOff, _block) + +/** + Temporarily changes the logging level for the configured RKLogComponent and executes the block. Any logging + statements executed within the body of the block for the current logging component will log at the new + logging level. After the block has finished execution, the logging level is restored to its previous state. + */ +#define RKLogWithLevelWhileExecutingBlock(_level, _block) \ + RKLogToComponentWithLevelWhileExecutingBlock(RKLogComponent, _level, _block) + + +/** + Temporarily turns off logging for current logging component during execution of the block. + After the block has finished execution, the logging level is restored to its previous state. + */ +#define RKLogSilenceWhileExecutingBlock(_block) \ + RKLogToComponentWithLevelWhileExecutingBlock(RKLogComponent, RKLogLevelOff, _block) + + +/** + Set the Default Log Level + + Based on the presence of the DEBUG flag, we default the logging for the RestKit parent component + to Info or Warning. + + You can override this setting by defining RKLogLevelDefault as a pre-processor macro. + */ +#ifndef RKLogLevelDefault + #ifdef DEBUG + #define RKLogLevelDefault RKLogLevelInfo + #else + #define RKLogLevelDefault RKLogLevelWarning + #endif +#endif + +/** + Configure RestKit logging from environment variables. + (Use Option + Command + R to set Environment Variables prior to run.) + + For example to configure the equivalent of setting the following in code: + RKLogConfigureByName("RestKit/Network", RKLogLevelTrace); + + Define an environment variable named 'RKLogLevel.RestKit.Network' and set its value to "Trace" + + See lcl_config_components_RK.h for configurable RestKit logging components. + + Valid values are the following: + Default or 0 + Critical or 1 + Error or 2 + Warning or 3 + Info or 4 + Debug or 5 + Trace or 6 + */ +void RKLogConfigureFromEnvironment(void); + +/** + Logs extensive information about an NSError generated as the results + of a failed key-value validation error. + */ +void RKLogValidationError(NSError *error); + +#ifdef _COREDATADEFINES_H +/** + Logs extensive information an NSError generated as the result of a + failed Core Data interaction, such as the execution of a fetch request + or the saving of a managed object context. + + The error will be logged to the RestKit/CoreData component with an + error level of RKLogLevelError regardless of the current logging context + at invocation time. + */ +void RKLogCoreDataError(NSError *error); +#endif + +/** + Logs the value of an NSUInteger as a binary string. Useful when + examining integers containing bitmasked values. + */ +void RKLogIntegerAsBinary(NSUInteger); diff --git a/Pods/RestKit/Code/Support/RKLog.m b/Pods/RestKit/Code/Support/RKLog.m new file mode 100644 index 0000000..100798e --- /dev/null +++ b/Pods/RestKit/Code/Support/RKLog.m @@ -0,0 +1,213 @@ +// +// RKLog.m +// RestKit +// +// Created by Blake Watters on 6/10/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKLog.h" + +@interface RKNSLogLogger : NSObject <RKLogging> +@end + +#if RKLOG_USE_NSLOGGER && __has_include("LCLNSLogger_RK.h") + #import "LCLNSLogger_RK.h" + #define RKLOG_CLASS LCLNSLogger_RK + +#elif __has_include("DDLog.h") + #import "RKLumberjackLogger.h" + #define RKLOG_CLASS RKLumberjackLogger + +#else + #define RKLOG_CLASS RKNSLogLogger +#endif + +// Hook into Objective-C runtime to configure logging when we are loaded +@interface RKLogInitializer : NSObject +@end + +@implementation RKLogInitializer + ++ (void)load +{ + RKlcl_configure_by_name("RestKit*", RKLogLevelDefault); + RKlcl_configure_by_name("App", RKLogLevelDefault); + if (RKGetLoggingClass() == Nil) RKSetLoggingClass([RKLOG_CLASS class]); + RKLogInfo(@"RestKit logging initialized..."); +} + +@end + +static Class <RKLogging> RKLoggingClass; + +Class <RKLogging> RKGetLoggingClass(void) +{ + return RKLoggingClass; +} + +void RKSetLoggingClass(Class <RKLogging> loggingClass) +{ + RKLoggingClass = loggingClass; +} + +@implementation RKNSLogLogger + ++ (void)logWithComponent:(_RKlcl_component_t)component + level:(_RKlcl_level_t)level + path:(const char *)file + line:(uint32_t)line + function:(const char *)function + format:(NSString *)format, ... +{ + va_list args; + va_start(args, format); + NSString *message = [[NSString alloc] initWithFormat:format arguments:args]; + va_end(args); + const char *fileName = (fileName = strrchr(file, '/')) ? fileName + 1 : file; + NSLog(@"%s %s:%s:%d %@", _RKlcl_level_header_1[level], _RKlcl_component_header[component], fileName, line, message); +} + +@end + +int RKLogLevelForString(NSString *, NSString *); + +void RKLogConfigureFromEnvironment(void) +{ + static NSString *logComponentPrefix = @"RKLogLevel."; + + NSDictionary *envVars = [[NSProcessInfo processInfo] environment]; + + for (NSString *envVarName in [envVars allKeys]) { + if ([envVarName hasPrefix:logComponentPrefix]) { + NSString *logLevel = [envVars valueForKey:envVarName]; + NSString *logComponent = [envVarName stringByReplacingOccurrencesOfString:logComponentPrefix withString:@""]; + logComponent = [logComponent stringByReplacingOccurrencesOfString:@"." withString:@"/"]; + + const char *log_component_c_str = [logComponent cStringUsingEncoding:NSUTF8StringEncoding]; + int log_level_int = RKLogLevelForString(logLevel, envVarName); + RKLogConfigureByName(log_component_c_str, log_level_int); + } + } +} + + +int RKLogLevelForString(NSString *logLevel, NSString *envVarName) +{ + // Forgive the user if they specify the full name for the value i.e. "RKLogLevelDebug" instead of "Debug" + logLevel = [logLevel stringByReplacingOccurrencesOfString:@"RKLogLevel" withString:@""]; + + if ([logLevel isEqualToString:@"Off"] || + [logLevel isEqualToString:@"0"]) { + return RKLogLevelOff; + } + else if ([logLevel isEqualToString:@"Critical"] || + [logLevel isEqualToString:@"1"]) { + return RKLogLevelCritical; + } + else if ([logLevel isEqualToString:@"Error"] || + [logLevel isEqualToString:@"2"]) { + return RKLogLevelError; + } + else if ([logLevel isEqualToString:@"Warning"] || + [logLevel isEqualToString:@"3"]) { + return RKLogLevelWarning; + } + else if ([logLevel isEqualToString:@"Info"] || + [logLevel isEqualToString:@"4"]) { + return RKLogLevelInfo; + } + else if ([logLevel isEqualToString:@"Debug"] || + [logLevel isEqualToString:@"5"]) { + return RKLogLevelDebug; + } + else if ([logLevel isEqualToString:@"Trace"] || + [logLevel isEqualToString:@"6"]) { + return RKLogLevelTrace; + } + else if ([logLevel isEqualToString:@"Default"]) { + return RKLogLevelDefault; + } + else { + NSString *errorMessage = [NSString stringWithFormat:@"The value: \"%@\" for the environment variable: \"%@\" is invalid. \ + \nThe log level must be set to one of the following values \ + \n Default or 0 \ + \n Critical or 1 \ + \n Error or 2 \ + \n Warning or 3 \ + \n Info or 4 \ + \n Debug or 5 \ + \n Trace or 6\n", logLevel, envVarName]; + @throw [NSException exceptionWithName:NSInvalidArgumentException reason:errorMessage userInfo:nil]; + + return -1; + } +} + +void RKLogIntegerAsBinary(NSUInteger bitMask) +{ + NSUInteger bit = ~(NSUIntegerMax >> 1); + NSMutableString *string = [NSMutableString string]; + do { + [string appendString:(((NSUInteger)bitMask & bit) ? @"1" : @"0")]; + } while (bit >>= 1); + + NSLog(@"Value of %ld in binary: %@", (long)bitMask, string); +} + +void RKLogValidationError(NSError *error) +{ +#ifdef _COREDATADEFINES_H + if ([[error domain] isEqualToString:NSCocoaErrorDomain]) { + NSDictionary *userInfo = [error userInfo]; + NSArray *errors = [userInfo valueForKey:@"NSDetailedErrors"]; + if (errors) { + for (NSError *detailedError in errors) { + NSDictionary *subUserInfo = [detailedError userInfo]; + RKLogError(@"Detailed Error\n \ + NSLocalizedDescriptionKey:\t\t%@\n \ + NSValidationKeyErrorKey:\t\t\t%@\n \ + NSValidationPredicateErrorKey:\t%@\n \ + NSValidationObjectErrorKey:\n%@\n", + [subUserInfo valueForKey:NSLocalizedDescriptionKey], + [subUserInfo valueForKey:NSValidationKeyErrorKey], + [subUserInfo valueForKey:NSValidationPredicateErrorKey], + [subUserInfo valueForKey:NSValidationObjectErrorKey]); + } + } else { + RKLogError(@"Validation Error\n \ + NSLocalizedDescriptionKey:\t\t%@\n \ + NSValidationKeyErrorKey:\t\t\t%@\n \ + NSValidationPredicateErrorKey:\t%@\n \ + NSValidationObjectErrorKey:\n%@\n", + [userInfo valueForKey:NSLocalizedDescriptionKey], + [userInfo valueForKey:NSValidationKeyErrorKey], + [userInfo valueForKey:NSValidationPredicateErrorKey], + [userInfo valueForKey:NSValidationObjectErrorKey]); + } + return; + } +#endif + RKLogError(@"Validation Error: %@ (userInfo: %@)", error, [error userInfo]); +} + +#ifdef _COREDATADEFINES_H +void RKLogCoreDataError(NSError *error) +{ + RKLogToComponentWithLevelWhileExecutingBlock(RKlcl_cRestKitCoreData, RKLogLevelError, ^{ + RKLogValidationError(error); + }); +} +#endif diff --git a/Pods/RestKit/Code/Support/RKLumberjackLogger.h b/Pods/RestKit/Code/Support/RKLumberjackLogger.h new file mode 100644 index 0000000..c77def6 --- /dev/null +++ b/Pods/RestKit/Code/Support/RKLumberjackLogger.h @@ -0,0 +1,17 @@ +// +// RKLumberjackLogger.h +// Pods +// +// Created by C_Lindberg,Carl on 10/31/14. +// +// + +#import <Foundation/Foundation.h> + +#if __has_include("DDLog.h") +#import "RKLog.h" + +@interface RKLumberjackLogger : NSObject <RKLogging> +@end + +#endif diff --git a/Pods/RestKit/Code/Support/RKLumberjackLogger.m b/Pods/RestKit/Code/Support/RKLumberjackLogger.m new file mode 100644 index 0000000..cdf0d51 --- /dev/null +++ b/Pods/RestKit/Code/Support/RKLumberjackLogger.m @@ -0,0 +1,110 @@ +// +// RKLumberjackLogger.m +// Pods +// +// Created by C_Lindberg,Carl on 10/31/14. +// +// + +#if __has_include("DDLog.h") +#import "RKLumberjackLogger.h" +#import "DDLog.h" + +@implementation RKLumberjackLogger + ++ (int)ddLogLevelFromRKLogLevel:(_RKlcl_level_t)rkLevel +{ + switch (rkLevel) + { + case RKLogLevelOff: return LOG_LEVEL_OFF; + case RKLogLevelCritical: return LOG_LEVEL_ERROR; + case RKLogLevelError: return LOG_LEVEL_ERROR; + case RKLogLevelWarning: return LOG_LEVEL_WARN; + case RKLogLevelInfo: return LOG_LEVEL_INFO; + case RKLogLevelDebug: return LOG_LEVEL_DEBUG; + case RKLogLevelTrace: return LOG_LEVEL_VERBOSE; + } + + return LOG_LEVEL_DEBUG; +} + ++ (int)ddLogFlagFromRKLogLevel:(_RKlcl_level_t)rkLevel +{ + switch (rkLevel) + { + case RKLogLevelOff: return 0; + case RKLogLevelCritical: return LOG_FLAG_ERROR; + case RKLogLevelError: return LOG_FLAG_ERROR; + case RKLogLevelWarning: return LOG_FLAG_WARN; + case RKLogLevelInfo: return LOG_FLAG_INFO; + case RKLogLevelDebug: return LOG_FLAG_DEBUG; + case RKLogLevelTrace: return LOG_FLAG_VERBOSE; + } + + return LOG_FLAG_DEBUG; +} + ++ (_RKlcl_level_t)rkLogLevelFromDDLogLevel:(int)ddLogLevel +{ + if (ddLogLevel & LOG_FLAG_VERBOSE) return RKLogLevelTrace; + if (ddLogLevel & LOG_FLAG_DEBUG) return RKLogLevelDebug; + if (ddLogLevel & LOG_FLAG_INFO) return RKLogLevelInfo; + if (ddLogLevel & LOG_FLAG_WARN) return RKLogLevelWarning; + if (ddLogLevel & LOG_FLAG_ERROR) return RKLogLevelError; + + return RKLogLevelOff; +} + + +#pragma mark RKLogging + ++ (void)logWithComponent:(_RKlcl_component_t)component + level:(_RKlcl_level_t)level + path:(const char *)path + line:(uint32_t)line + function:(const char *)function + format:(NSString *)format, ... +{ + va_list args; + va_start(args, format); + + int flag = [self ddLogFlagFromRKLogLevel:level]; + int componentLevel = [self ddLogLevelFromRKLogLevel:_RKlcl_component_level[component]]; + BOOL async = LOG_ASYNC_ENABLED && ((flag & LOG_FLAG_ERROR) == 0); + + [DDLog log:async + level:componentLevel + flag:flag + context:0x524B5F00 + component + file:path function:function line:line + tag:nil + format:format args:args]; + va_end(args); +} + +@end + +/* Create a DDRegisteredDynamicLogging class for each RestKit component */ + +#import "lcl_config_components_RK.h" + +#undef _RKlcl_component +#define _RKlcl_component(_identifier, _header, _name) \ + @interface RKLumberjackLog##_identifier : NSObject <DDRegisteredDynamicLogging> \ + @end \ + @implementation RKLumberjackLog##_identifier \ + + (int)ddLogLevel { \ + _RKlcl_level_t level = _RKlcl_component_level[RKlcl_c##_identifier]; \ + return [RKLumberjackLogger ddLogLevelFromRKLogLevel:level]; \ + } \ + + (void)ddSetLogLevel:(int)logLevel { \ + RKLogConfigureByName(_name, [RKLumberjackLogger rkLogLevelFromDDLogLevel:logLevel]); \ + } \ + @end + +RKLCLComponentDefinitions + +#undef _RKlcl_component + + +#endif diff --git a/Pods/RestKit/Code/Support/RKMIMETypeSerialization.h b/Pods/RestKit/Code/Support/RKMIMETypeSerialization.h new file mode 100644 index 0000000..071869a --- /dev/null +++ b/Pods/RestKit/Code/Support/RKMIMETypeSerialization.h @@ -0,0 +1,97 @@ +// +// RKMIMETypeSerialization.h +// RestKit +// +// Created by Blake Watters on 5/18/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKMIMETypes.h" +#import "RKSerialization.h" + +/** + The `RKMIMETypeSerialization` class provides support for the registration of classes conforming to the `RKSerialization` protocol by MIME Type and the serialization and deserialization of content by MIME Type. Serialization implementations may be registered by an exact string match (i.e. 'application/json' for a JSON serialization implementation) or by regular expression to match MIME Type by pattern. + */ +@interface RKMIMETypeSerialization : NSObject + +///--------------------------------------- +/// @name Managing MIME Type Registrations +///--------------------------------------- + +/** + Registers the given serialization class to handle content for the given MIME Type identifier. + + MIME Types may be given as either a string or as a regular expression that matches the MIME Types for which the given serialization should handle. Serializations are searched in the reverse order of their registration. If a registration is made for an already registered MIME Type, the new registration will take precedence. + + @param serializationClass The class conforming to the RKSerialization protocol to be registered as handling the given MIME Type. + @param MIMETypeStringOrRegularExpression A string or regular expression specifying the MIME Type(s) that given serialization implementation is to be registered as handling. + */ ++ (void)registerClass:(Class<RKSerialization>)serializationClass forMIMEType:(id)MIMETypeStringOrRegularExpression; + +/** + Unregisters the given serialization class from handling any MIME Types. + + After this method is invoked, invocations of `serializationForMIMEType:` will no longer return the unregistered serialization class. + + @param serializationClass The class conforming to the `RKSerialization` protocol to be unregistered. + */ ++ (void)unregisterClass:(Class<RKSerialization>)serializationClass; + +/** + Returns the serialization class registered to handle the given MIME Type. + + Searches the registrations in reverse order for the first serialization implementation registered to handle the given MIME Type. Matches are determined by doing a lowercase string comparison if the MIME Type was registered with a string identifier or by evaluating a regular expression match against the given MIME Type if registered with a regular expression. + + @param MIMEType The MIME Type for which to return the registered `RKSerialization` conformant class. + @return A class conforming to the RKSerialization protocol registered for the given MIME Type or nil if none was found. + */ ++ (Class<RKSerialization>)serializationClassForMIMEType:(NSString *)MIMEType; + +/** + Returns a set containing the string values for all MIME Types for which a serialization implementation has been registered. + + @return An `NSSet` object whose elements are `NSString` values enumerating the registered MIME Types. + */ ++ (NSSet *)registeredMIMETypes; + +///--------------------------------------------------------- +/// @name Serializing and Deserializing Content by MIME Type +///--------------------------------------------------------- + +/** + Deserializes and returns a Foundation object representation of the given UTF-8 encoded data in the serialization format for the given MIME Type. + + On invocation, searches the registrations by invoking `serializationClassForMIMEType:` with the given MIME Type and then invokes `objectFromData:error:` on the `RKSerialization` conformant class returned. If no serialization implementation is found to handle the given MIME Type, nil is returned and the given error pointer will be set to an NSError object with the `RKMissingSerializationForMIMETypeError` code. + + @param data The UTF-8 encoded data representation of the object to be deserialized. + @param MIMEType The MIME Type of the serialization format the data is in. + @param error A pointer to an NSError object. + @return A Foundation object from the serialized data in data, or nil if an error occurs. + */ ++ (id)objectFromData:(NSData *)data MIMEType:(NSString *)MIMEType error:(NSError **)error; + +/** + Serializes and returns a UTF-8 encoded data representation of the given Foundation object in the serialization format for the given MIME Type. + + On invocation, searches the registrations by invoking `serializationClassForMIMEType:` with the given MIME Type and then invokes `objectFromData:error:` on the `RKSerialization` conformant class returned. If no serialization implementation is found to handle the given MIME Type, nil is returned and the given error pointer will be set to an NSError object with the `RKMissingSerializationForMIMETypeError` code. + + @param object The Foundation object to serialized. + @param MIMEType The MIME Type of the serialization format the data is in. + @param error A pointer to an NSError object. + @return A Foundation object from the serialized data in data, or nil if an error occurs. + */ ++ (NSData *)dataFromObject:(id)object MIMEType:(NSString *)MIMEType error:(NSError **)error; + +@end diff --git a/Pods/RestKit/Code/Support/RKMIMETypeSerialization.m b/Pods/RestKit/Code/Support/RKMIMETypeSerialization.m new file mode 100644 index 0000000..caf4145 --- /dev/null +++ b/Pods/RestKit/Code/Support/RKMIMETypeSerialization.m @@ -0,0 +1,182 @@ +// +// RKMIMETypeSerialization.m +// RestKit +// +// Created by Blake Watters on 5/18/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKMIMETypeSerialization.h" +#import "RKErrors.h" +#import "RKSerialization.h" +#import "RKLog.h" +#import "RKURLEncodedSerialization.h" +#import "RKNSJSONSerialization.h" + +// Define logging component +#undef RKLogComponent +#define RKLogComponent RKlcl_cRestKitSupport + +@interface RKMIMETypeSerializationRegistration : NSObject + +@property (nonatomic, strong) id MIMETypeStringOrRegularExpression; +@property (nonatomic, assign) Class<RKSerialization> serializationClass; + +- (instancetype)initWithMIMEType:(id)MIMETypeStringOrRegularExpression serializationClass:(Class<RKSerialization>)serializationClass NS_DESIGNATED_INITIALIZER; +- (BOOL)matchesMIMEType:(NSString *)MIMEType; +@end + +@implementation RKMIMETypeSerializationRegistration + +- (instancetype)initWithMIMEType:(id)MIMETypeStringOrRegularExpression serializationClass:(Class<RKSerialization>)serializationClass +{ + NSParameterAssert(MIMETypeStringOrRegularExpression); + NSParameterAssert(serializationClass); + NSAssert([MIMETypeStringOrRegularExpression isKindOfClass:[NSString class]] + || [MIMETypeStringOrRegularExpression isKindOfClass:[NSRegularExpression class]], + @"Can only register a serialization class for a MIME Type by string or regular expression."); + + self = [super init]; + if (self) { + self.MIMETypeStringOrRegularExpression = MIMETypeStringOrRegularExpression; + self.serializationClass = serializationClass; + } + + return self; +} + +- (BOOL)matchesMIMEType:(NSString *)MIMEType +{ + return RKMIMETypeInSet(MIMEType, [NSSet setWithObject:self.MIMETypeStringOrRegularExpression]); +} + +- (NSString *)description +{ + NSString *mimeTypeDescription = [self.MIMETypeStringOrRegularExpression isKindOfClass:[NSRegularExpression class]] ? + [NSString stringWithFormat:@"MIME Type =~ \"%@\"", self.MIMETypeStringOrRegularExpression] : + [NSString stringWithFormat:@"MIME Type == \"%@\"", self.MIMETypeStringOrRegularExpression]; + return [NSString stringWithFormat:@"<%@: %p, %@, serializationClass=%@>", + NSStringFromClass([self class]), self, mimeTypeDescription, NSStringFromClass(self.serializationClass)]; +} + +@end + +@interface RKMIMETypeSerialization () +@property (nonatomic, strong) NSMutableArray *registrations; +@end + +@implementation RKMIMETypeSerialization + ++ (RKMIMETypeSerialization *)sharedSerialization +{ + static RKMIMETypeSerialization *sharedInstance = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedInstance = [[RKMIMETypeSerialization alloc] init]; + [sharedInstance addRegistrationsForKnownSerializations]; + }); + return sharedInstance; + +} + +- (instancetype)init +{ + self = [super init]; + if (self) { + self.registrations = [NSMutableArray new]; + } + + return self; +} + +- (void)addRegistrationsForKnownSerializations +{ + // URL Encoded + [self.registrations addObject:[[RKMIMETypeSerializationRegistration alloc] initWithMIMEType:RKMIMETypeFormURLEncoded + serializationClass:[RKURLEncodedSerialization class]]]; + // JSON + [self.registrations addObject:[[RKMIMETypeSerializationRegistration alloc] initWithMIMEType:RKMIMETypeJSON + serializationClass:[RKNSJSONSerialization class]]]; +} + +#pragma mark - Public + ++ (Class<RKSerialization>)serializationClassForMIMEType:(NSString *)MIMEType +{ + for (RKMIMETypeSerializationRegistration *registration in [[self sharedSerialization].registrations reverseObjectEnumerator]) { + if ([registration matchesMIMEType:MIMEType]) { + return registration.serializationClass; + } + } + return nil; +} + ++ (void)registerClass:(Class<RKSerialization>)serializationClass forMIMEType:(id)MIMETypeStringOrRegularExpression +{ + RKMIMETypeSerializationRegistration *registration = [[RKMIMETypeSerializationRegistration alloc] initWithMIMEType:MIMETypeStringOrRegularExpression serializationClass:serializationClass]; + [[self sharedSerialization].registrations addObject:registration]; +} + ++ (void)unregisterClass:(Class<RKSerialization>)serializationClass +{ + NSArray *registrationsCopy = [[self sharedSerialization].registrations copy]; + for (RKMIMETypeSerializationRegistration *registration in registrationsCopy) { + if (registration.serializationClass == serializationClass) { + [[self sharedSerialization].registrations removeObject:registration]; + } + } +} + ++ (NSSet *)registeredMIMETypes +{ + return [NSSet setWithArray:[[self sharedSerialization].registrations valueForKey:@"MIMETypeStringOrRegularExpression"]]; +} + ++ (id)objectFromData:(NSData *)data MIMEType:(NSString *)MIMEType error:(NSError **)error +{ + NSParameterAssert(data); + NSParameterAssert(MIMEType); + + Class<RKSerialization> serializationClass = [self serializationClassForMIMEType:MIMEType]; + if (!serializationClass) { + if (error) { + NSString* errorMessage = [NSString stringWithFormat:@"Cannot deserialize data: No serialization registered for MIME Type '%@'", MIMEType]; + NSDictionary *userInfo = @{ NSLocalizedDescriptionKey : errorMessage, RKMIMETypeErrorKey : MIMEType }; + *error = [NSError errorWithDomain:RKErrorDomain code:RKUnsupportedMIMETypeError userInfo:userInfo]; + } + return nil; + } + + return [serializationClass objectFromData:data error:error]; +} + ++ (id)dataFromObject:(id)object MIMEType:(NSString *)MIMEType error:(NSError **)error +{ + NSParameterAssert(object); + NSParameterAssert(MIMEType); + Class<RKSerialization> serializationClass = [self serializationClassForMIMEType:MIMEType]; + if (!serializationClass) { + if (error) { + NSString* errorMessage = [NSString stringWithFormat:@"Cannot deserialize data: No serialization registered for MIME Type '%@'", MIMEType]; + NSDictionary *userInfo = @{ NSLocalizedDescriptionKey : errorMessage, RKMIMETypeErrorKey : MIMEType }; + *error = [NSError errorWithDomain:RKErrorDomain code:RKUnsupportedMIMETypeError userInfo:userInfo]; + } + return nil; + } + + return [serializationClass dataFromObject:object error:error]; +} + +@end diff --git a/Pods/RestKit/Code/Support/RKMIMETypes.h b/Pods/RestKit/Code/Support/RKMIMETypes.h new file mode 100644 index 0000000..8415d28 --- /dev/null +++ b/Pods/RestKit/Code/Support/RKMIMETypes.h @@ -0,0 +1,52 @@ +// +// RKMIMETypes.h +// RestKit +// +// Created by Blake Watters on 5/18/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#ifdef __cplusplus +extern "C" { +#endif + +/** + MIME Type Constants + */ + +/// MIME Type application/json +extern NSString * const RKMIMETypeJSON; + +/// MIME Type application/x-www-form-urlencoded +extern NSString * const RKMIMETypeFormURLEncoded; + +/// MIME Type application/xml +extern NSString * const RKMIMETypeXML; + +/// MIME Type text/xml +extern NSString * const RKMIMETypeTextXML; + +/** + Returns `YES` if the given MIME Type matches any MIME Type identifiers in the given set. + + @param MIMEType The MIME Type to evaluate the match for. + @param MIMETypes An `NSSet` object who entries are `NSString` or `NSRegularExpression` objects specifying MIME Types. + @return `YES` if the given MIME Type matches any identifier in the set, else `NO`. + */ +BOOL RKMIMETypeInSet(NSString *MIMEType, NSSet *MIMETypes); + +#ifdef __cplusplus +} +#endif diff --git a/Pods/RestKit/Code/Support/RKMIMETypes.m b/Pods/RestKit/Code/Support/RKMIMETypes.m new file mode 100644 index 0000000..c22ff5f --- /dev/null +++ b/Pods/RestKit/Code/Support/RKMIMETypes.m @@ -0,0 +1,44 @@ +// +// RKMIMETypes.m +// RestKit +// +// Created by Blake Watters on 5/18/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKMIMETypes.h" + +NSString * const RKMIMETypeJSON = @"application/json"; +NSString * const RKMIMETypeFormURLEncoded = @"application/x-www-form-urlencoded"; +NSString * const RKMIMETypeXML = @"application/xml"; +NSString * const RKMIMETypeTextXML = @"text/xml"; + +BOOL RKMIMETypeInSet(NSString *MIMEType, NSSet *MIMETypes) +{ + for (id MIMETypeStringOrRegularExpression in MIMETypes) { + if ([MIMETypeStringOrRegularExpression isKindOfClass:[NSString class]]) { + if ([[MIMETypeStringOrRegularExpression lowercaseString] isEqualToString:[MIMEType lowercaseString]]) return YES; + } else if ([MIMETypeStringOrRegularExpression isKindOfClass:[NSRegularExpression class]]) { + NSRegularExpression *regex = (NSRegularExpression *) MIMETypeStringOrRegularExpression; + NSUInteger numberOfMatches = [regex numberOfMatchesInString:[MIMEType lowercaseString] options:0 range:NSMakeRange(0, [MIMEType length])]; + if (numberOfMatches > 0) return YES; + } else { + NSString *reason = [NSString stringWithFormat:@"Unable to evaluate match for MIME Type '%@': expected an `NSString` or `NSRegularExpression`, got a `%@`", MIMEType, NSStringFromClass([MIMEType class])]; + @throw [NSException exceptionWithName:NSInvalidArgumentException reason:reason userInfo:nil]; + } + } + + return NO; +} diff --git a/Pods/RestKit/Code/Support/RKMacros.h b/Pods/RestKit/Code/Support/RKMacros.h new file mode 100644 index 0000000..2852d08 --- /dev/null +++ b/Pods/RestKit/Code/Support/RKMacros.h @@ -0,0 +1,51 @@ +// +// RKMacros.h +// RestKit +// +// Created by Jawwad Ahmad on 7/18/12. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#ifndef RestKit_RKMacros_h +#define RestKit_RKMacros_h + +/* + Instead of using the normal DEPRECATED_ATTRIBUTE use DEPRECATED_ATTRIBUTE_MESSAGE(message) + to display a helpful recommendation message along with the deprecation message. + */ +#ifndef DEPRECATED_ATTRIBUTE_MESSAGE +#define DEPRECATED_ATTRIBUTE_MESSAGE(message) __attribute__((deprecated (message))) +#endif + +/* + Add this macro before each category implementation, so we don't have to use + -all_load or -force_load to load object files from static libraries that only contain + categories and no classes. + See http://developer.apple.com/library/mac/#qa/qa2006/qa1490.html for more info. + + Shamelessly borrowed from Three20 + */ +#define RK_FIX_CATEGORY_BUG(name) @interface RK_FIX_CATEGORY_BUG##name @end \ +@implementation RK_FIX_CATEGORY_BUG##name @end + +/* + Raises an `NSInvalidArgumentException` in the event that the given value is not an instance of the given class or an instance of any class that inherits from that class. + */ +#define RKAssertValueIsKindOfClass(value, expectedClass) \ +if (! [value isKindOfClass:expectedClass]) { \ +[NSException raise:NSInvalidArgumentException format:@"%@ invoked with invalid input value: expected a `%@`, but instead got a `%@`", [self class], expectedClass, [value class]]; \ +} + +#endif diff --git a/Pods/RestKit/Code/Support/RKNSJSONSerialization.h b/Pods/RestKit/Code/Support/RKNSJSONSerialization.h new file mode 100644 index 0000000..598e250 --- /dev/null +++ b/Pods/RestKit/Code/Support/RKNSJSONSerialization.h @@ -0,0 +1,29 @@ +// +// RKNSJSONSerialization.h +// RestKit +// +// Created by Blake Watters on 8/31/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKSerialization.h" + +/** + The `RKNSJSONSerialization` class conforms to the `RKSerialization` protocol and provides support for the serialization and deserialization of data in the JSON format using the Apple provided `NSJSONSerialization` class. This is the default JSON implementation for RestKit. + + @see http://www.json.org/ + */ +@interface RKNSJSONSerialization : NSObject <RKSerialization> +@end diff --git a/Pods/RestKit/Code/Support/RKNSJSONSerialization.m b/Pods/RestKit/Code/Support/RKNSJSONSerialization.m new file mode 100644 index 0000000..3b277ea --- /dev/null +++ b/Pods/RestKit/Code/Support/RKNSJSONSerialization.m @@ -0,0 +1,35 @@ +// +// RKNSJSONSerialization.m +// RestKit +// +// Created by Blake Watters on 8/31/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKNSJSONSerialization.h" + +@implementation RKNSJSONSerialization + ++ (id)objectFromData:(NSData *)data error:(NSError **)error +{ + return [NSJSONSerialization JSONObjectWithData:data options:0 error:error]; +} + ++ (NSData *)dataFromObject:(id)object error:(NSError **)error +{ + return [NSJSONSerialization dataWithJSONObject:object options:0 error:error]; +} + +@end diff --git a/Pods/RestKit/Code/Support/RKOperationStateMachine.h b/Pods/RestKit/Code/Support/RKOperationStateMachine.h new file mode 100644 index 0000000..bd7ea49 --- /dev/null +++ b/Pods/RestKit/Code/Support/RKOperationStateMachine.h @@ -0,0 +1,158 @@ +// +// RKOperationStateMachine.h +// RestKit +// +// Created by Blake Watters on 4/11/13. +// Copyright (c) 2013 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import <Foundation/Foundation.h> + +/** + The `RKOperationStateMachine` class provides an implementation of a state machine that is suitable for implementing a concurrent `NSOperation` subclass via composition. The concurrency mechanism is a dispatch queue. The state machine takes care of correctly implementing all aspects of a concurrent `NSOperation` including: + 1. Asynchronous execution + 1. Locking + 1. Appropriate state transitions + 1. Cancellation + 1. State Instrospection + + The state machine begins its life in the ready state. Upon start, the state transitions to executing and a user-supplied execution block is invoked on the operation's dispatch queue. The operation remains in the executing state until it is finished. Just before the operation is finished, a finalization block is invoked. In the event that the operation is cancelled, then an optional cancellation block is invoked. Note that because cancellation semantics can vary widely, a cancelled operation is merely flagged as being cancelled. It is the responsibility of the operation to ensure that a cancelled operation is finished as soon as possible. + + The underlying implementation of the state machine is backed by [TransitionKit](http://github.com/blakewatters/TransitionKit) + */ +@interface RKOperationStateMachine : NSObject + +- (instancetype)init __attribute__((unavailable("Invoke initWithOperation: instead."))); + +///----------------------------------- +/// @name Initializing a State Machine +///----------------------------------- + +/** + Initializes a new state machine object with a given operation and dispatch queue. + + @param operation The operation that the receiver is modeling the concurrent lifecycle of. + @param dispatchQueue The dispatch queue on which the operation executes concurrently. + @return The receiver, initialized with the given operation and queue. + */ +- (instancetype)initWithOperation:(NSOperation *)operation dispatchQueue:(dispatch_queue_t)dispatchQueue NS_DESIGNATED_INITIALIZER; + +///----------------------- +/// @name Inspecting State +///----------------------- + +/** + Returns a Boolean value that indicates if the receiver is ready to be started. + + @return `YES` if the receiver is ready to be started, else `NO`. + */ +@property (nonatomic, getter=isReady, readonly) BOOL ready; + +/** + Returns a Boolean value that indicates if the receiver is executing. + + @return `YES` if the receiver is executing, else `NO`. + */ +@property (nonatomic, getter=isExecuting, readonly) BOOL executing; + +/** + Returns a Boolean value that indicates if the receiver has been cancelled. + + @return `YES` if the receiver has been cancelled, else `NO`. + */ +@property (nonatomic, getter=isCancelled, readonly) BOOL cancelled; + +/** + Returns a Boolean value that indicates if the receiver has finished executing. + + @return `YES` if the receiver is finished, else `NO`. + */ +@property (nonatomic, getter=isFinished, readonly) BOOL finished; + +///-------------------- +/// @name Firing Events +///-------------------- + +/** + Starts the operation by transitioning into the executing state and asychronously invoking the execution block on the operation dispatch queue. + */ +- (void)start; + +/** + Finishes the operation by transitioning from the executing state to the finished state. The state transition is executed asynchronously on the operation dispatch queue. Invokes the finalization block just before the state changes from executing to finished. + */ +- (void)finish; + +/** + Marks the operation is being cancelled. Cancellation results in state transition because cancellation semantics can vary widely. Once the cancellation flag has been set (`isCancelled` return `YES`), the cancellation block is invoked asynchronously on the operation dispatch queue. The operation must be finished as soon as possible. + */ +- (void)cancel; + +///--------------------------------- +/// @name Configuring Event Handlers +///--------------------------------- + +/** + Sets a block to be executed on the operation dispatch queue once the operation transitions to the executing state. + + @param block The block to be executed. + */ +- (void)setExecutionBlock:(void (^)(void))block; + +/** + Sets a block to be executed when the operation is cancelled. The block will be invoked on the operation dispatch queue. Cancellation does not trigger any state transition -- the operation must still be explicitly finished as soon as possible. If appropriate, the operation may be finished within the body of the cancellation block. + + @param block The block to be executed. + */ +- (void)setCancellationBlock:(void (^)(void))block; + +/** + Sets a block to be executed when the operation is about to transition from executing to finished. This block is invoked regardless of the cancellation state. This block should be used to perform any last minute cleanup or preparation before the operation finishes. + + @param block The block to be executed. + */ +- (void)setFinalizationBlock:(void (^)(void))block; + +///------------------------------ +/// @name Accessing Configuration +///------------------------------ + +/** + The operation that the receiver is modeling the lifecycle of. + */ +@property (nonatomic, weak, readonly) NSOperation *operation; + +/** + The dispatch queue within which the state machine executes. + */ +@property (nonatomic, assign, readonly) dispatch_queue_t dispatchQueue; + +///------------------------------------------ +/// @name Performing Blocks that Mutate State +///------------------------------------------ + +/** + Executes a block after acquiring an exclusive lock on the receiver. This enables the block to safely mutate the state of the operation. The execution context of the block is not changed -- it is always executed within the caller's thread context. If you wish to guarantee execution on the dispatch queue backing the state machine then you must dispatch onto the queue before submitting your block for execution. + + @param block The block to execute after acquiring an exclusive lock on the receiver. + */ +- (void)performBlockWithLock:(void (^)())block; + +@end + +/** + Raised when an unexpected error has occurred. + */ +extern NSString *const RKOperationFailureException; diff --git a/Pods/RestKit/Code/Support/RKOperationStateMachine.m b/Pods/RestKit/Code/Support/RKOperationStateMachine.m new file mode 100644 index 0000000..33bb1ab --- /dev/null +++ b/Pods/RestKit/Code/Support/RKOperationStateMachine.m @@ -0,0 +1,209 @@ +// +// RKOperationStateMachine.m +// RestKit +// +// Created by Blake Watters on 4/11/13. +// Copyright (c) 2013 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "TransitionKit.h" +#import "RKOperationStateMachine.h" + +NSString *const RKOperationFailureException = @"RKOperationFailureException"; + +static NSString *const RKOperationStateReady = @"Ready"; +static NSString *const RKOperationStateExecuting = @"Executing"; +static NSString *const RKOperationStateFinished = @"Finished"; + +static NSString *const RKOperationEventStart = @"start"; +static NSString *const RKOperationEventFinish = @"finish"; + +static NSString *const RKOperationLockName = @"org.restkit.operation.lock"; + +@interface RKOperationStateMachine () +@property (nonatomic, strong) TKStateMachine *stateMachine; +@property (nonatomic, weak, readwrite) NSOperation *operation; +@property (nonatomic, assign, readwrite) dispatch_queue_t dispatchQueue; +@property (nonatomic, assign, getter = isCancelled) BOOL cancelled; +@property (nonatomic, copy) void (^cancellationBlock)(void); +@property (nonatomic, strong) NSRecursiveLock *lock; +@end + +@implementation RKOperationStateMachine + +- (instancetype)initWithOperation:(NSOperation *)operation dispatchQueue:(dispatch_queue_t)dispatchQueue +{ + if (! operation) [NSException raise:NSInvalidArgumentException format:@"Invalid argument: `operation` cannot be nil."]; + if (! dispatchQueue) [NSException raise:NSInvalidArgumentException format:@"Invalid argument: `dispatchQueue` cannot be nil."]; + self = [super init]; + if (self) { + self.operation = operation; + self.dispatchQueue = dispatchQueue; + self.stateMachine = [TKStateMachine new]; + self.lock = [NSRecursiveLock new]; + [self.lock setName:RKOperationLockName]; + + // NOTE: State transitions are guarded by a lock via start/finish/cancel action methods + TKState *readyState = [TKState stateWithName:RKOperationStateReady]; + __weak __typeof(self)weakSelf = self; + [readyState setWillExitStateBlock:^(TKState *state, TKTransition *transition) { + [weakSelf.operation willChangeValueForKey:@"isReady"]; + }]; + [readyState setDidExitStateBlock:^(TKState *state, TKTransition *transition) { + [weakSelf.operation didChangeValueForKey:@"isReady"]; + }]; + + TKState *executingState = [TKState stateWithName:RKOperationStateExecuting]; + [executingState setWillEnterStateBlock:^(TKState *state, TKTransition *transition) { + [weakSelf.operation willChangeValueForKey:@"isExecuting"]; + }]; + // NOTE: isExecuting KVO for `setDidEnterStateBlock:` configured below in `setExecutionBlock` + [executingState setWillExitStateBlock:^(TKState *state, TKTransition *transition) { + [weakSelf.operation willChangeValueForKey:@"isExecuting"]; + }]; + [executingState setDidExitStateBlock:^(TKState *state, TKTransition *transition) { + [weakSelf.operation didChangeValueForKey:@"isExecuting"]; + }]; + [executingState setDidEnterStateBlock:^(TKState *state, TKTransition *transition) { + [NSException raise:NSInternalInconsistencyException format:@"You must configure an execution block via `setExecutionBlock:`."]; + }]; + + TKState *finishedState = [TKState stateWithName:RKOperationStateFinished]; + [finishedState setWillEnterStateBlock:^(TKState *state, TKTransition *transition) { + [weakSelf.operation willChangeValueForKey:@"isFinished"]; + }]; + [finishedState setDidEnterStateBlock:^(TKState *state, TKTransition *transition) { + [weakSelf.operation didChangeValueForKey:@"isFinished"]; + }]; + [finishedState setWillExitStateBlock:^(TKState *state, TKTransition *transition) { + [weakSelf.operation willChangeValueForKey:@"isFinished"]; + }]; + [finishedState setDidExitStateBlock:^(TKState *state, TKTransition *transition) { + [weakSelf.operation didChangeValueForKey:@"isFinished"]; + }]; + + [self.stateMachine addStates:@[ readyState, executingState, finishedState ]]; + + TKEvent *startEvent = [TKEvent eventWithName:RKOperationEventStart transitioningFromStates:@[ readyState ] toState:executingState]; + TKEvent *finishEvent = [TKEvent eventWithName:RKOperationEventFinish transitioningFromStates:@[ executingState ] toState:finishedState]; + [self.stateMachine addEvents:@[ startEvent, finishEvent ]]; + + self.stateMachine.initialState = readyState; + [self.stateMachine activate]; + } + return self; +} + +- (instancetype)init +{ + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:[NSString stringWithFormat:@"%@ Failed to call designated initializer. Invoke initWithOperation: instead.", + NSStringFromClass([self class])] + userInfo:nil]; +} + +- (BOOL)isReady +{ + return [self.stateMachine isInState:RKOperationStateReady]; +} + +- (BOOL)isExecuting +{ + return [self.stateMachine isInState:RKOperationStateExecuting]; +} + +- (BOOL)isFinished +{ + return [self.stateMachine isInState:RKOperationStateFinished]; +} + +- (void)start +{ + if (! self.dispatchQueue) [NSException raise:NSInternalInconsistencyException format:@"You must configure an `operationQueue`."]; + [self performBlockWithLock:^{ + NSError *error = nil; + BOOL success = [self.stateMachine fireEvent:RKOperationEventStart userInfo:nil error:&error]; + if (! success) [NSException raise:RKOperationFailureException format:@"The operation unexpectedly failed to start due to an error: %@", error]; + }]; +} + +- (void)finish +{ + // Ensure that we are finished from the operation queue + dispatch_async(self.dispatchQueue, ^{ + [self performBlockWithLock:^{ + NSError *error = nil; + BOOL success = [self.stateMachine fireEvent:RKOperationEventFinish userInfo:nil error:&error]; + if (! success) [NSException raise:RKOperationFailureException format:@"The operation unexpectedly failed to finish due to an error: %@", error]; + }]; + }); +} + +- (void)cancel +{ + if ([self isCancelled] || [self isFinished]) return; + [self performBlockWithLock:^{ + self.cancelled = YES; + }]; + + if (self.cancellationBlock) { + dispatch_async(self.dispatchQueue, ^{ + [self performBlockWithLock:self.cancellationBlock]; + }); + } +} + +- (void)setExecutionBlock:(void (^)(void))block +{ + __weak __typeof(self)weakSelf = self; + TKState *executingState = [self.stateMachine stateNamed:RKOperationStateExecuting]; + [executingState setDidEnterStateBlock:^(TKState *state, TKTransition *transition) { + [weakSelf.operation didChangeValueForKey:@"isExecuting"]; + dispatch_async(weakSelf.dispatchQueue, ^{ + block(); + }); + }]; +} + +- (void)setFinalizationBlock:(void (^)(void))block +{ + __weak __typeof(self)weakSelf = self; + TKState *finishedState = [self.stateMachine stateNamed:RKOperationStateFinished]; + [finishedState setWillEnterStateBlock:^(TKState *state, TKTransition *transition) { + [weakSelf performBlockWithLock:^{ + // Must emit KVO as we are replacing the block configured in `initWithOperation:queue:` + [weakSelf.operation willChangeValueForKey:@"isFinished"]; + block(); + }]; + }]; +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@"<%@: %p (for %@:%p), state: %@, cancelled: %@>", + [self class], self, + [self.operation class], self.operation, + self.stateMachine.currentState.name, + ([self isCancelled] ? @"YES" : @"NO")]; +} + +- (void)performBlockWithLock:(void (^)())block +{ + [self.lock lock]; + block(); + [self.lock unlock]; +} + +@end diff --git a/Pods/RestKit/Code/Support/RKPathUtilities.h b/Pods/RestKit/Code/Support/RKPathUtilities.h new file mode 100644 index 0000000..c7155d7 --- /dev/null +++ b/Pods/RestKit/Code/Support/RKPathUtilities.h @@ -0,0 +1,62 @@ +// +// RKPathUtilities.h +// RestKit +// +// Created by Blake Watters on 12/9/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// + +#import <Foundation/Foundation.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Returns the path to the Application Data directory for the executing application. On iOS, this is a sandboxed path specific for the executing application. On OS X, this is an application specific path under `NSApplicationSupportDirectory` (i.e. ~/Application Support). + + @return The full path to the application data directory. + */ +NSString *RKApplicationDataDirectory(void); + +/** + Returns a path to the root caches directory used by RestKit for storage. On iOS, this is a sanboxed path specific for the executing application. On OS X, this is an application specific path under NSCachesDirectory (i.e. ~/Library/Caches). + + @return The full path to the Caches directory. + */ +NSString *RKCachesDirectory(void); + +/** + Ensures that a directory exists at a given path by checking for the existence of the directory and creating it if it does not exist. + + @param path The path to ensure a directory exists at. + @param error On input, a pointer to an error object. + @returns A Boolean value indicating if the directory exists. + */ +BOOL RKEnsureDirectoryExistsAtPath(NSString *path, NSError **error); + +/** + Returns a MIME Type for a given path by using the Core Services framework. + + For example, given a string with the path `@"/Users/blake/Documents/monkey.json"` `@"application/json"` would be returned as the MIME Type. + + @param path The path to return the MIME Type for. + @return The expected MIME Type of the resource identified by the path or nil if unknown. + */ +NSString *RKMIMETypeFromPathExtension(NSString *path); + +/** + Excludes the item at a given path from backup via iTunes and/or iCloud using the approaches detailed in "Apple Technical Q&A QA1719". + + Excluding a path from backup can be necessary in order to conform to the iCloud Data Storage Guidelines. Please refer to the following links for more details: + + 1. [iCloud Data Storage Guidelines](https://developer.apple.com/icloud/documentation/data-storage/) + 1. [Technical Q&A QA1719](http://developer.apple.com/library/ios/#qa/qa1719/_index.html) + + @param path The path to the item that is to be excluded from backup. + */ +void RKSetExcludeFromBackupAttributeForItemAtPath(NSString *path); + +#ifdef __cplusplus +} +#endif diff --git a/Pods/RestKit/Code/Support/RKPathUtilities.m b/Pods/RestKit/Code/Support/RKPathUtilities.m new file mode 100644 index 0000000..373657a --- /dev/null +++ b/Pods/RestKit/Code/Support/RKPathUtilities.m @@ -0,0 +1,153 @@ +// +// RKPathUtilities.m +// RestKit +// +// Created by Blake Watters on 12/9/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// + +#if TARGET_OS_IPHONE +#import <MobileCoreServices/UTType.h> +#import <UIKit/UIDevice.h> +#else +#import <CoreServices/CoreServices.h> +#endif +#import <Availability.h> +#import <sys/xattr.h> +#import "RKPathUtilities.h" +#import "RKLog.h" + +NSString *RKExecutableName(void); + +NSString *RKApplicationDataDirectory(void) +{ +#if TARGET_OS_IPHONE + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); + return ([paths count] > 0) ? paths[0] : nil; +#else + NSFileManager *sharedFM = [NSFileManager defaultManager]; + + NSArray *possibleURLs = [sharedFM URLsForDirectory:NSApplicationSupportDirectory + inDomains:NSUserDomainMask]; + NSURL *appSupportDir = nil; + NSURL *appDirectory = nil; + + if ([possibleURLs count] >= 1) { + appSupportDir = possibleURLs[0]; + } + + if (appSupportDir) { + appDirectory = [appSupportDir URLByAppendingPathComponent:RKExecutableName()]; + return [appDirectory path]; + } + + return nil; +#endif +} + +NSString *RKExecutableName(void) +{ + NSString *executableName = [[[NSBundle mainBundle] executablePath] lastPathComponent]; + if (nil == executableName) { + RKLogWarning(@"Unable to determine CFBundleExecutable: storing data under RestKit directory name."); + executableName = @"RestKit"; + } + + return executableName; +} + +NSString *RKCachesDirectory(void) +{ +#if TARGET_OS_IPHONE + return NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0]; +#else + NSString *path = nil; + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); + if ([paths count]) { + path = [paths[0] stringByAppendingPathComponent:RKExecutableName()]; + } + + return path; +#endif +} + +BOOL RKEnsureDirectoryExistsAtPath(NSString *path, NSError **error) +{ + BOOL isDirectory; + if ([[NSFileManager defaultManager] fileExistsAtPath:path isDirectory:&isDirectory]) { + if (isDirectory) { + // Exists at a path and is a directory, we're good + if (error) *error = nil; + return YES; + } + } + + // Create the directory and any intermediates + NSError *errorReference = (error == nil) ? nil : *error; + if (! [[NSFileManager defaultManager] createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:&errorReference]) { + RKLogError(@"Failed to create requested directory at path '%@': %@", path, errorReference); + return NO; + } + + return YES; +} + +static NSDictionary *RKDictionaryOfFileExtensionsToMIMETypes() +{ + return @{ @"json": @"application/json" }; +} + +NSString *RKMIMETypeFromPathExtension(NSString *path) +{ + NSString *pathExtension = [path pathExtension]; + CFStringRef uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (__bridge CFStringRef)pathExtension, NULL); + if (uti != NULL) { + CFStringRef mime = UTTypeCopyPreferredTagWithClass(uti, kUTTagClassMIMEType); + CFRelease(uti); + if (mime != NULL) { + NSString *type = [NSString stringWithString:(__bridge NSString *)mime]; + CFRelease(mime); + return type; + } + } + + // Consult our internal dictionary of mappings if not found + return [RKDictionaryOfFileExtensionsToMIMETypes() valueForKey:pathExtension]; +} + +void RKSetExcludeFromBackupAttributeForItemAtPath(NSString *path) +{ + NSCParameterAssert(path); + NSCAssert([[NSFileManager defaultManager] fileExistsAtPath:path], @"Cannot set Exclude from Backup attribute for non-existant item at path: '%@'", path); + +#if __IPHONE_OS_VERSION_MIN_REQUIRED + NSError *error = nil; + NSURL *URL = [NSURL fileURLWithPath:path]; + + NSComparisonResult order = [[UIDevice currentDevice].systemVersion compare:@"5.1" options:NSNumericSearch]; + if (order == NSOrderedSame || order == NSOrderedDescending) { + // On iOS >= 5.1, we can use the resource value API's. Note that we probe the iOS version number directly because the `setResourceValue:forKey:` symbol is defined in iOS 4.0 and greater, but performs no operation when invoked until iOS 5.1 + BOOL success = [URL setResourceValue:@(YES) forKey:NSURLIsExcludedFromBackupKey error:&error]; + if (!success) { + RKLogError(@"Failed to exclude item at path '%@' from Backup: %@", path, error); + } + } else { + order = [[UIDevice currentDevice].systemVersion compare:@"5.0.1" options: NSNumericSearch]; + if (order == NSOrderedSame || order == NSOrderedDescending) { + // On iOS 5.0.1 we must use the extended attribute API's directly + const char* filePath = [[URL path] fileSystemRepresentation]; + const char* attrName = "com.apple.MobileBackup"; + u_int8_t attrValue = 1; + + int result = setxattr(filePath, attrName, &attrValue, sizeof(attrValue), 0, 0); + if (result != 0) { + RKLogError(@"Failed to exclude item at path '%@' from Backup. setxattr returned result code %d", path, result); + } + } else { + RKLogWarning(@"Unable to exclude item from backup: resource value and extended attribute APIs are only available on iOS 5.0.1 and up"); + } + } +#else + RKLogDebug(@"Not built for iOS -- excluding path from Backup is not possible."); +#endif +} diff --git a/Pods/RestKit/Code/Support/RKSerialization.h b/Pods/RestKit/Code/Support/RKSerialization.h new file mode 100644 index 0000000..073c73d --- /dev/null +++ b/Pods/RestKit/Code/Support/RKSerialization.h @@ -0,0 +1,54 @@ +// +// RKSerialization.h +// RestKit +// +// Created by Blake Watters on 10/1/10. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +/** + The `RKSerialization` protocol declares two methods that a class must implement so that it can provide support for serializing objects to and deserializing objects from UTF-8 encoded data representations of a serialization format such as JSON or XML. Serialization implementations typically handle data in a given MIME Type (i.e. `application/json`) and may be registered with the `RKMIMETypeSerialization` class. + + @see `RKMIMETypeSerialization` + */ +@protocol RKSerialization <NSObject> + +///------------------------------ +/// @name Deserializing an Object +///------------------------------ + +/** + Deserializes and returns the given data in the format supported by the receiver (i.e. JSON, XML, etc) as a Foundation object representation. + + @param data The UTF-8 encoded data representation of the object to be deserialized. + @param error A pointer to an `NSError` object. + @return A Foundation object from the serialized data in data, or nil if an error occurs. + */ ++ (id)objectFromData:(NSData *)data error:(NSError **)error; + +///---------------------------- +/// @name Serializing an Object +///---------------------------- + +/** + Serializes and returns a UTF-8 encoded data representation of the given Foundation object in the format supported by the receiver (i.e. JSON, XML, etc). + + @param object The object to be serialized. + @param error A pointer to an NSError object. + @return A data representation of the given object in UTF-8 encoding, or nil if an error occurred. + */ ++ (NSData *)dataFromObject:(id)object error:(NSError **)error; + +@end diff --git a/Pods/RestKit/Code/Support/RKStringTokenizer.h b/Pods/RestKit/Code/Support/RKStringTokenizer.h new file mode 100644 index 0000000..721671d --- /dev/null +++ b/Pods/RestKit/Code/Support/RKStringTokenizer.h @@ -0,0 +1,51 @@ +// +// RKStringTokenizer.h +// RestKit +// +// Created by Blake Watters on 7/30/12. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import <Foundation/Foundation.h> + +/** + The `RKStringTokenizer` class provides an interface for tokenizing input text into a set of searchable words. Diacritics are removed and the input text is tokenized case insensitively. A set of stop words can be optionally trimmed from the result token set. + */ +@interface RKStringTokenizer : NSObject + +///------------------------------- +/// @name Configuring Tokenization +///------------------------------- + +/** + The set of stop words that are to be removed from the token set. + + Defaults to nil. + */ +@property (nonatomic, strong) NSSet *stopWords; + +///---------------------------------- +/// @name Tokenizing a String of Text +///---------------------------------- + +/** + Tokenizes the given string by folding it case and diacritic insensitively and then splitting it apart using the the word unit delimiters for the current locale. If a set of stop words has been provided, the resulting token set will have the stop words subtracted. + + @param string A string of text you wish to tokenize. + @returns A set of searchable text tokens extracted from the given string. + */ +- (NSSet *)tokenize:(NSString *)string; + +@end diff --git a/Pods/RestKit/Code/Support/RKStringTokenizer.m b/Pods/RestKit/Code/Support/RKStringTokenizer.m new file mode 100644 index 0000000..48e3644 --- /dev/null +++ b/Pods/RestKit/Code/Support/RKStringTokenizer.m @@ -0,0 +1,42 @@ +// +// RKStringTokenizer.m +// RestKit +// +// Created by Blake Watters on 7/30/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// + +#import "RKStringTokenizer.h" + +@implementation RKStringTokenizer + +- (NSSet *)tokenize:(NSString *)string +{ + NSMutableSet *tokens = [NSMutableSet set]; + + CFLocaleRef locale = CFLocaleCopyCurrent(); + + // Remove diacratics and lowercase our input text + NSString *tokenizeText = string = [string stringByFoldingWithOptions:kCFCompareCaseInsensitive|kCFCompareDiacriticInsensitive locale:[NSLocale systemLocale]]; + CFStringTokenizerRef tokenizer = CFStringTokenizerCreate(kCFAllocatorDefault, (__bridge CFStringRef)tokenizeText, CFRangeMake(0, CFStringGetLength((__bridge CFStringRef)tokenizeText)), kCFStringTokenizerUnitWord, locale); + CFStringTokenizerTokenType tokenType = kCFStringTokenizerTokenNone; + + while (kCFStringTokenizerTokenNone != (tokenType = CFStringTokenizerAdvanceToNextToken(tokenizer))) { + CFRange tokenRange = CFStringTokenizerGetCurrentTokenRange(tokenizer); + + NSRange range = NSMakeRange(tokenRange.location, tokenRange.length); + NSString *token = [string substringWithRange:range]; + + [tokens addObject:token]; + } + + CFRelease(tokenizer); + CFRelease(locale); + + // Remove any stop words + if (self.stopWords) [tokens minusSet:self.stopWords]; + + return tokens; +} + +@end diff --git a/Pods/RestKit/Code/Support/RKURLEncodedSerialization.h b/Pods/RestKit/Code/Support/RKURLEncodedSerialization.h new file mode 100644 index 0000000..3c109d2 --- /dev/null +++ b/Pods/RestKit/Code/Support/RKURLEncodedSerialization.h @@ -0,0 +1,74 @@ +// +// RKURLEncodedSerialization.h +// RestKit +// +// Created by Blake Watters on 9/4/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKSerialization.h" + +/** + The `RKURLEncodedSerialization` class conforms to the `RKSerialization` protocol and provides support for the serialization and deserialization of URL encoded data. URL encoding is used to replace certain characters in a string with equivalent percent escape sequences. The list of characters replaced by the implementation are designed as illegal URL characters by RFC 3986. URL encoded data is used for the submission of HTML forms with the MIME Type `application/x-www-form-urlencoded`. + + @see http://www.w3.org/TR/html401/interact/forms.html + @see http://www.ietf.org/rfc/rfc3986.txt + */ +@interface RKURLEncodedSerialization : NSObject <RKSerialization> + +@end + +/** + Creates and returns a new `NSDictionary` object from the given URL-encoded string, using the specified encoding. + + The dictionary is constructed by splitting the string into components using the `&` character as the delimiter. The results array of strings is then split again using the `=` character as the delimiter. Each resulting key and value delimited by the `=` character is then URL decoded and added a resulting dictionary. The process is across the entire string. Any extraneous `=` characters not delimiting a key and value are ignored. The corresponding values for any keys that appear multiple times within the string be coalesced into an `NSArray` of values. + + @param URLEncodedString A URL-encoded string that is to be parsed into an `NSDictionary`. + @param encoding The encoding to use when URL-decoding the components of the given string. If you are uncertain of the correct encoding, you should use UTF-8 (NSUTF8StringEncoding), which is the encoding designated by RFC 3986 as the correct encoding for use in URLs. + @return An `NSDictionary` object containing the keys and values deserialized from the URL-encoded string. + */ +NSDictionary *RKDictionaryFromURLEncodedStringWithEncoding(NSString *URLEncodedString, NSStringEncoding encoding); + +/** + Returns a URL-encoded `NSString` object containing the entries in the given `NSDictionary` object. + + The dictionary is created by collecting each key-value pair, URL-encoding a string representation of the key-value pair, and then joining the components with "&". + + @param dictionary The dictionary from to construct the URL-encoded string. + @param encoding The encoding to use in constructing the URL-encoded string. If you are uncertain of the correct encoding, you should use UTF-8 (NSUTF8StringEncoding), which is the encoding designated by RFC 3986 as the correct encoding for use in URLs. + @return A new `NSString` object in the given encoding containing a URL-encoded serialization of the entries in the given dictionary. + @see `AFQueryStringFromParametersWithEncoding` + */ +NSString *RKURLEncodedStringFromDictionaryWithEncoding(NSDictionary *dictionary, NSStringEncoding encoding); + +/** + Returns a copy of the given string with the characters that are unsafe for use in a URL query string replaced with the equivalent percent escape sequences. + + @param string The string to be escaped. + @param encoding The encoding to use in constructing the URL-encoded string. If you are uncertain of the correct encoding, you should use UTF-8 (NSUTF8StringEncoding), which is the encoding designated by RFC 3986 as the correct encoding for use in URLs. + @return A new `NSString` object in the given encoding with the query string unsafe characters replaced with percent escape sequences. + */ +NSString *RKPercentEscapedQueryStringFromStringWithEncoding(NSString *string, NSStringEncoding encoding); + +/** + Creates and returns a new `NSDictionary` object containing the keys and values in the query string of the given string. + + The given string is searched for a `?` character denoting the beginning of the query parameters. If none is found, the entire string is treated as a URL encoded query string. The parameters are extracted from the query string by invoking `RKDictionaryFromURLEncodedStringWithEncoding()` with the query string. + + @param string A string containing a query string that is to be tokenized into a dictionary of parameters. + @param encoding The encoding to use in constructing the URL-encoded string. If you are uncertain of the correct encoding, you should use UTF-8 (NSUTF8StringEncoding), which is the encoding designated by RFC 3986 as the correct encoding for use in URLs. + @return An `NSDictionary` object containing the keys and values contained in the query string of the given string. + */ +NSDictionary *RKQueryParametersFromStringWithEncoding(NSString *string, NSStringEncoding encoding); diff --git a/Pods/RestKit/Code/Support/RKURLEncodedSerialization.m b/Pods/RestKit/Code/Support/RKURLEncodedSerialization.m new file mode 100644 index 0000000..09f7ae7 --- /dev/null +++ b/Pods/RestKit/Code/Support/RKURLEncodedSerialization.m @@ -0,0 +1,190 @@ +// +// RKURLEncodedSerialization.m +// RestKit +// +// Created by Blake Watters on 9/4/12. +// Copyright (c) 2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "RKURLEncodedSerialization.h" + +#pragma mark - AFNetworking + +// Taken from https://github.com/AFNetworking/AFNetworking/blob/49f2f8c9a907977ec1b3afb182404ae0a6bce883/AFNetworking/AFURLRequestSerialization.m + +static NSString * const RKAFCharactersToBeEscapedInQueryString = @":/?&=;+!@#$()',*"; + +static NSString * RKAFPercentEscapedQueryStringKeyFromStringWithEncoding(NSString *string, NSStringEncoding encoding) { + static NSString * const RKAFCharactersToLeaveUnescapedInQueryStringPairKey = @"[]."; + + return (__bridge_transfer NSString *)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (__bridge CFStringRef)string, (__bridge CFStringRef)RKAFCharactersToLeaveUnescapedInQueryStringPairKey, (__bridge CFStringRef)RKAFCharactersToBeEscapedInQueryString, CFStringConvertNSStringEncodingToEncoding(encoding)); +} + +static NSString * AFPercentEscapedQueryStringValueFromStringWithEncoding(NSString *string, NSStringEncoding encoding) { + return (__bridge_transfer NSString *)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (__bridge CFStringRef)string, NULL, (__bridge CFStringRef)RKAFCharactersToBeEscapedInQueryString, CFStringConvertNSStringEncodingToEncoding(encoding)); +} + +#pragma mark - + +@interface RKAFQueryStringPair : NSObject +@property (readwrite, nonatomic, strong) id field; +@property (readwrite, nonatomic, strong) id value; + +- (instancetype)initWithField:(id)field value:(id)value NS_DESIGNATED_INITIALIZER; + +- (NSString *)URLEncodedStringValueWithEncoding:(NSStringEncoding)stringEncoding; +@end + +@implementation RKAFQueryStringPair + +- (instancetype)initWithField:(id)field value:(id)value { + self = [super init]; + if (!self) { + return nil; + } + + self.field = field; + self.value = value; + + return self; +} + +- (NSString *)URLEncodedStringValueWithEncoding:(NSStringEncoding)stringEncoding { + if (!self.value || [self.value isEqual:[NSNull null]]) { + return RKAFPercentEscapedQueryStringKeyFromStringWithEncoding([self.field description], stringEncoding); + } else { + return [NSString stringWithFormat:@"%@=%@", RKAFPercentEscapedQueryStringKeyFromStringWithEncoding([self.field description], stringEncoding), AFPercentEscapedQueryStringValueFromStringWithEncoding([self.value description], stringEncoding)]; + } +} + +@end + +#pragma mark - + +extern NSArray * RKAFQueryStringPairsFromDictionary(NSDictionary *dictionary); +extern NSArray * RKAFQueryStringPairsFromKeyAndValue(NSString *key, id value); + +static NSString * RKAFQueryStringFromParametersWithEncoding(NSDictionary *parameters, NSStringEncoding stringEncoding) { + NSMutableArray *mutablePairs = [NSMutableArray array]; + for (RKAFQueryStringPair *pair in RKAFQueryStringPairsFromDictionary(parameters)) { + [mutablePairs addObject:[pair URLEncodedStringValueWithEncoding:stringEncoding]]; + } + + return [mutablePairs componentsJoinedByString:@"&"]; +} + +NSArray * RKAFQueryStringPairsFromDictionary(NSDictionary *dictionary) { + return RKAFQueryStringPairsFromKeyAndValue(nil, dictionary); +} + +NSArray * RKAFQueryStringPairsFromKeyAndValue(NSString *key, id value) { + NSMutableArray *mutableQueryStringComponents = [NSMutableArray array]; + + NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"description" ascending:YES selector:@selector(compare:)]; + + if ([value isKindOfClass:[NSDictionary class]]) { + NSDictionary *dictionary = value; + // Sort dictionary keys to ensure consistent ordering in query string, which is important when deserializing potentially ambiguous sequences, such as an array of dictionaries + for (id nestedKey in [dictionary.allKeys sortedArrayUsingDescriptors:@[ sortDescriptor ]]) { + id nestedValue = dictionary[nestedKey]; + if (nestedValue) { + [mutableQueryStringComponents addObjectsFromArray:RKAFQueryStringPairsFromKeyAndValue((key ? [NSString stringWithFormat:@"%@[%@]", key, nestedKey] : nestedKey), nestedValue)]; + } + } + } else if ([value isKindOfClass:[NSArray class]]) { + NSArray *array = value; + for (id nestedValue in array) { + [mutableQueryStringComponents addObjectsFromArray:RKAFQueryStringPairsFromKeyAndValue([NSString stringWithFormat:@"%@[]", key], nestedValue)]; + } + } else if ([value isKindOfClass:[NSSet class]]) { + NSSet *set = value; + for (id obj in [set sortedArrayUsingDescriptors:@[ sortDescriptor ]]) { + [mutableQueryStringComponents addObjectsFromArray:RKAFQueryStringPairsFromKeyAndValue(key, obj)]; + } + } else { + [mutableQueryStringComponents addObject:[[RKAFQueryStringPair alloc] initWithField:key value:value]]; + } + + return mutableQueryStringComponents; +} + +#pragma mark - RestKit + +@implementation RKURLEncodedSerialization + ++ (id)objectFromData:(NSData *)data error:(NSError **)error +{ + NSString *string = [NSString stringWithUTF8String:[data bytes]]; + return RKDictionaryFromURLEncodedStringWithEncoding(string, NSUTF8StringEncoding); +} + ++ (NSData *)dataFromObject:(id)object error:(NSError **)error +{ + NSString *string = RKURLEncodedStringFromDictionaryWithEncoding(object, NSUTF8StringEncoding); + return [string dataUsingEncoding:NSUTF8StringEncoding]; +} + +@end + +NSDictionary *RKDictionaryFromURLEncodedStringWithEncoding(NSString *URLEncodedString, NSStringEncoding encoding) +{ + NSMutableDictionary *queryComponents = [NSMutableDictionary dictionary]; + for (NSString *keyValuePairString in [URLEncodedString componentsSeparatedByString:@"&"]) { + NSArray *keyValuePairArray = [keyValuePairString componentsSeparatedByString:@"="]; + if ([keyValuePairArray count] < 2) continue; // Verify that there is at least one key, and at least one value. Ignore extra = signs + NSString *key = [keyValuePairArray[0] stringByReplacingPercentEscapesUsingEncoding:encoding]; + NSString *value = [keyValuePairArray[1] stringByReplacingPercentEscapesUsingEncoding:encoding]; + + // URL spec says that multiple values are allowed per key + id results = queryComponents[key]; + if (results) { + if ([results isKindOfClass:[NSMutableArray class]]) { + [(NSMutableArray *)results addObject:value]; + } else { + // On second occurrence of the key, convert into an array + NSMutableArray *values = [NSMutableArray arrayWithObjects:results, value, nil]; + queryComponents[key] = values; + } + } else { + queryComponents[key] = value; + } + } + return queryComponents; +} + +NSString *RKURLEncodedStringFromDictionaryWithEncoding(NSDictionary *dictionary, NSStringEncoding encoding) +{ + return RKAFQueryStringFromParametersWithEncoding(dictionary, encoding); +} + +// This replicates `AFPercentEscapedQueryStringPairMemberFromStringWithEncoding`. Should send PR exposing non-static version +NSString *RKPercentEscapedQueryStringFromStringWithEncoding(NSString *string, NSStringEncoding encoding) +{ + // Escape characters that are legal in URIs, but have unintentional semantic significance when used in a query string parameter + static NSString * const kAFLegalCharactersToBeEscaped = @":/.?&=;+!@$()~"; + + return (__bridge_transfer NSString *)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (__bridge CFStringRef)string, NULL, (__bridge CFStringRef)kAFLegalCharactersToBeEscaped, CFStringConvertNSStringEncodingToEncoding(encoding)); +} + +NSDictionary *RKQueryParametersFromStringWithEncoding(NSString *string, NSStringEncoding encoding) +{ + NSRange chopRange = [string rangeOfString:@"?"]; + if (chopRange.length > 0) { + chopRange.location += 1; // we want inclusive chopping up *through *"?" + if (chopRange.location < [string length]) string = [string substringFromIndex:chopRange.location]; + } + return RKDictionaryFromURLEncodedStringWithEncoding(string, encoding); +} + diff --git a/Pods/RestKit/Code/Support/lcl_config_components_RK.h b/Pods/RestKit/Code/Support/lcl_config_components_RK.h new file mode 100644 index 0000000..e710254 --- /dev/null +++ b/Pods/RestKit/Code/Support/lcl_config_components_RK.h @@ -0,0 +1,63 @@ +// +// lcl_config_components_RK.h +// RestKit +// +// Created by Blake Watters on 6/8/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// +// The lcl_config_components_RK.h file is used to define the application's log +// components. +// +// Use the code +// +// _RKlcl_component(<identifier>, <header>, <name>) +// +// for defining a log component, where +// +// - <identifier> is the unique name of a log component which is used in calls +// to RKlcl_log etc. A symbol 'RKlcl_c<identifier>' is automatically created for +// each log component. +// +// - <header> is a C string in UTF-8 which should be used by a logging back-end +// when writing a log message for the log component. The header is a technical +// key for identifying a log component's messages. It is recommended to use +// a 'Reverse ICANN' naming scheme when the header contains grouping +// information, e.g. 'example.main.component1'. +// +// - <name> is a C string in UTF-8 which contains the name of the log component +// and its grouping information in a non-technical, human-readable way +// which could be used by a user interface. Groups should be separated by the +// path separator '/', e.g. 'Example/Main/Component 1'. +// + + +// +// RestKit Logging Components +// + +#define RKLCLComponentDefinitions \ +_RKlcl_component(App, "app", "App") \ +_RKlcl_component(RestKit, "restkit", "RestKit") \ +_RKlcl_component(RestKitCoreData, "restkit.core_data", "RestKit/CoreData") \ +_RKlcl_component(RestKitCoreDataCache, "restkit.core_data.cache", "RestKit/CoreData/Cache") \ +_RKlcl_component(RestKitNetwork, "restkit.network", "RestKit/Network") \ +_RKlcl_component(RestKitNetworkCoreData, "restkit.network.core_data", "RestKit/Network/CoreData") \ +_RKlcl_component(RestKitObjectMapping, "restkit.object_mapping", "RestKit/ObjectMapping") \ +_RKlcl_component(RestKitSearch, "restkit.search", "RestKit/Search") \ +_RKlcl_component(RestKitSupport, "restkit.support", "RestKit/Support") \ +_RKlcl_component(RestKitTesting, "restkit.testing", "RestKit/Testing") \ +_RKlcl_component(RestKitUI, "restkit.ui", "RestKit/UI") diff --git a/Pods/RestKit/Code/Support/lcl_config_extensions_RK.h b/Pods/RestKit/Code/Support/lcl_config_extensions_RK.h new file mode 100644 index 0000000..6229343 --- /dev/null +++ b/Pods/RestKit/Code/Support/lcl_config_extensions_RK.h @@ -0,0 +1,20 @@ +// +// lcl_config_extensions_RK.h +// RestKit +// +// Created by Blake Watters on 6/8/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + diff --git a/Pods/RestKit/Code/Support/lcl_config_logger_RK.h b/Pods/RestKit/Code/Support/lcl_config_logger_RK.h new file mode 100644 index 0000000..64e2ffa --- /dev/null +++ b/Pods/RestKit/Code/Support/lcl_config_logger_RK.h @@ -0,0 +1,53 @@ +// +// lcl_config_logger_RK.h +// RestKit +// +// Created by Blake Watters on 6/8/11. +// Copyright (c) 2009-2012 RestKit. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// +// Integration with LibComponentLogging Core. +// + +// ARC/non-ARC autorelease pool +#define _RKlcl_logger_autoreleasepool_arc 0 +#if defined(__has_feature) +# if __has_feature(objc_arc) +# undef _RKlcl_logger_autoreleasepool_arc +# define _RKlcl_logger_autoreleasepool_arc 1 +# endif +#endif + +#if _RKlcl_logger_autoreleasepool_arc + #define _RKlcl_logger_autoreleasepool_begin @autoreleasepool { + #define _RKlcl_logger_autoreleasepool_end } +#else + #define _RKlcl_logger_autoreleasepool_begin NSAutoreleasePool *_RKlcl_logpool = [[NSAutoreleasePool alloc] init]; + #define _RKlcl_logger_autoreleasepool_end [_RKlcl_logpool release]; +#endif + + +#define _RKlcl_logger(_component, _level, _format, ...) { \ + _RKlcl_logger_autoreleasepool_begin \ + [RKGetLoggingClass() logWithComponent:_component \ + level:_level \ + path:__FILE__ \ + line:__LINE__ \ + function:__PRETTY_FUNCTION__ \ + format:_format, ## __VA_ARGS__]; \ + _RKlcl_logger_autoreleasepool_end \ +} + diff --git a/Pods/RestKit/LICENSE b/Pods/RestKit/LICENSE new file mode 100644 index 0000000..eb8d4bc --- /dev/null +++ b/Pods/RestKit/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2009-2012 The RestKit Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Pods/RestKit/README.md b/Pods/RestKit/README.md new file mode 100644 index 0000000..a963eac --- /dev/null +++ b/Pods/RestKit/README.md @@ -0,0 +1,629 @@ +# RestKit + +[![Build Status](http://img.shields.io/travis/RestKit/RestKit/development.svg?style=flat)](https://travis-ci.org/RestKit/RestKit) +[![Pod Version](http://img.shields.io/cocoapods/v/RestKit.svg?style=flat)](http://cocoadocs.org/docsets/RestKit/) +[![Pod Platform](http://img.shields.io/cocoapods/p/RestKit.svg?style=flat)](http://cocoadocs.org/docsets/RestKit/) +[![Pod License](http://img.shields.io/cocoapods/l/RestKit.svg?style=flat)](https://www.apache.org/licenses/LICENSE-2.0.html) +[![Visit our IRC channel](http://img.shields.io/badge/IRC-%23RestKit-green.svg?style=flat)](https://kiwiirc.com/client/irc.freenode.net/?nick=rkuser|?&theme=basic#RestKit) + +RestKit is a modern Objective-C framework for implementing RESTful web services clients on iOS and Mac OS X. It provides a powerful [object mapping](https://github.com/RestKit/RestKit/wiki/Object-mapping) engine that seamlessly integrates with [Core Data](http://developer.apple.com/library/mac/#documentation/cocoa/Conceptual/CoreData/cdProgrammingGuide.html) and a simple set of networking primitives for mapping HTTP requests and responses built on top of [AFNetworking](https://github.com/AFNetworking/AFNetworking). It has an elegant, carefully designed set of APIs that make accessing and modeling RESTful resources feel almost magical. For example, here's how to access the Twitter public timeline and turn the JSON contents into an array of Tweet objects: + +``` objective-c +@interface RKTweet : NSObject +@property (nonatomic, copy) NSNumber *userID; +@property (nonatomic, copy) NSString *username; +@property (nonatomic, copy) NSString *text; +@end + +RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RKTweet class]]; +[mapping addAttributeMappingsFromDictionary:@{ + @"user.name": @"username", + @"user.id": @"userID", + @"text": @"text" +}]; + +RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:mapping method:RKRequestMethodAny pathPattern:nil keyPath:nil statusCodes:nil]; +NSURL *url = [NSURL URLWithString:@"http://api.twitter.com/1/statuses/public_timeline.json"]; +NSURLRequest *request = [NSURLRequest requestWithURL:url]; +RKObjectRequestOperation *operation = [[RKObjectRequestOperation alloc] initWithRequest:request responseDescriptors:@[responseDescriptor]]; +[operation setCompletionBlockWithSuccess:^(RKObjectRequestOperation *operation, RKMappingResult *result) { + NSLog(@"The public timeline Tweets: %@", [result array]); +} failure:nil]; +[operation start]; +``` + +## Getting Started + +- [Download RestKit](https://github.com/RestKit/RestKit/releases) and play with the [examples](https://github.com/RestKit/RestKit/tree/development/Examples) for iPhone and Mac OS X +- First time with RestKit? Read the ["Overview"](#overview) section below and then check out the ["Getting Acquainted with RestKit"](https://github.com/RestKit/RKGist/blob/master/TUTORIAL.md) tutorial and [Object Mapping Reference](https://github.com/RestKit/RestKit/wiki/Object-mapping) documents in the wiki to jump right in. +- Upgrading from RestKit 0.9.x or 0.10.x? Read the ["Upgrading to RestKit 0.20.x"](https://github.com/RestKit/RestKit/wiki/Upgrading-from-v0.10.x-to-v0.20.0) guide in the wiki +- Adding RestKit to an existing [AFNetworking](https://github.com/AFNetworking/AFNetworking) application? Read the [AFNetworking Integration](https://github.com/RestKit/RestKit/wiki/AFNetworking-Integration) document to learn details about how the frameworks fit together. +- Review the [source code API documentation](http://cocoadocs.org/docsets/RestKit/) for a detailed look at the classes and API's in RestKit. A great place to start is [RKObjectManager](http://restkit.org/api/latest/Classes/RKObjectManager.html). +- Still need some help? Ask questions on [Stack Overflow](http://stackoverflow.com/questions/tagged/restkit) or the [mailing list](http://groups.google.com/group/restkit), ping us on [Twitter](http://twitter.com/RestKit) or chat with us on [IRC](https://kiwiirc.com/client/irc.freenode.net/?nick=rkuser|?&theme=basic#RestKit). + +## Overview + +RestKit is designed to be modular and each module strives to maintain a minimal set of dependencies across the framework and with the host platform. At the core of library sits the object mapping engine, which is responsible for transforming objects between representations (such as JSON/XML <-> local domain objects). + +### Object Mapping Fundamentals + +The object mapping engine is built on top of the [Key-Value Coding](https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/KeyValueCoding/Articles/KeyValueCoding.html) (KVC) informal protocol that is foundational to numerous Cocoa technologies such as key-value observing, bindings, and Core Data. Object mappings are expressed as pairs of KVC key paths that specify the source and destination attributes or relationships that are to be transformed. + +RestKit leverages the highly dynamic Objective-C runtime to infer the developers desired intent by examining the type of the source and destination properties and performing appropriate type transformations. For example, given a source key path of `created_at` that identifies a string within a parsed JSON document and a destination key path of `creationDate` that identifies an `NSDate` property on a target object, RestKit will transform the date from a string into an `NSDate` using an `NSDateFormatter`. Numerous other transformations are provided out of the box and the engine is pluggable to allow the developer to define new transformations or replace an existing transformation with a new implementation. + +The mapper fully supports both simple attribute as well as relationship mappings in which nested to-one or to-many child objects are mapped recursively. Through relationship mappings, one object mapping can be added to another to compose aggregate mappings that are capable of processing arbitrarily complex source documents. + +Object mapping is a deep topic and is explored in exhaustive detail in the [Object Mapping Guide](https://github.com/RestKit/RestKit/wiki/Object-mapping) on the wiki. + +### API Quickstart + +RestKit is broken into several modules that cleanly separate the mapping engine from the HTTP and Core Data integrations to provide maximum flexibility. Key classes in each module are highlighted below and each module is hyperlinked to the README.md contained within the source code. + +<table> + <tr><th colspan="2" style="text-align:center;"><a href="https://github.com/RestKit/RestKit/wiki/Object-mapping">Object Mapping</a></th></tr> + <tr> + <td><a href="http://restkit.org/api/latest/Classes/RKObjectMapping.html">RKObjectMapping</a></td> + <td>Encapsulates configuration for transforming object representations as expressed by key-value coding keypaths.</td> + </tr> + <tr> + <td><a href="http://restkit.org/api/latest/Classes/RKAttributeMapping.html">RKAttributeMapping</a></td> + <td>Specifies a desired transformation between attributes within an object or entity mapping in terms of a source and destination key path.</td> + </tr> + <tr> + <td><a href="http://restkit.org/api/latest/Classes/RKRelationshipMapping.html">RKRelationshipMapping</a></td> + <td>Specifies a desired mapping of a nested to-one or to-many child objects in in terms of a source and destination key path and an <tt>RKObjectMapping</tt> with which to map the attributes of the child object.</td> + </tr> + <tr> + <td><a href="http://restkit.org/api/latest/Classes/RKDynamicMapping.html">RKDynamicMapping</a></td> + <td>Specifies a flexible mapping in which the decision about which <tt>RKObjectMapping</tt> is to be used to process a given document is deferred to run time.</td> + </tr> + <tr> + <td><a href="http://restkit.org/api/latest/Classes/RKMapperOperation.html">RKMapperOperation</a></td> + <td>Provides an interface for mapping a deserialized document into a set of local domain objects.</td> + </tr> + <tr> + <td><a href="http://restkit.org/api/latest/Classes/RKMappingOperation.html">RKMappingOperation</a></td> + <td>An <tt>NSOperation</tt> that performs a mapping between object representations using an <tt>RKObjectMapping</tt>.</td> + </tr> + <tr><th colspan="2" style="text-align:center;"><a href="Code/Network/README.md">Networking</a></th></tr> + <tr> + <td><a href="http://restkit.org/api/latest/Classes/RKRequestDescriptor.html">RKRequestDescriptor</a></td> + <td>Describes a request that can be sent from the application to a remote web application for a given object type.</td> + </tr> + <tr> + <td><a href="http://restkit.org/api/latest/Classes/RKResponseDescriptor.html">RKResponseDescriptor</a></td> + <td>Describes an object mappable response that may be returned from a remote web application in terms of an object mapping, a key path, a <a href="http://cocoadocs.org/docsets/SOCKit/">SOCKit pattern</a> for matching the URL, and a set of status codes that define the circumstances in which the mapping is appropriate for a given response.</td> + </tr> + <tr> + <td><a href="http://restkit.org/api/latest/Classes/RKObjectParameterization.html">RKObjectParameterization</a></td> + <td>Performs mapping of a given object into an <tt>NSDictionary</tt> representation suitable for use as the parameters of an HTTP request.</td> + </tr> + <tr> + <td><a href="http://restkit.org/api/latest/Classes/RKObjectRequestOperation.html">RKObjectRequestOperation</a></td> + <td>An <tt>NSOperation</tt> that sends an HTTP request and performs object mapping on the parsed response body using the configurations expressed in a set of <tt>RKResponseDescriptor</tt> objects.</td> + </tr> + <tr> + <td><a href="http://restkit.org/api/latest/Classes/RKResponseMapper.html">RKResponseMapperOperation</a></td> + <td>An <tt>NSOperation</tt> that provides support for object mapping an <tt>NSHTTPURLResponse</tt> using a set of <tt>RKResponseDescriptor</tt> objects.</td> + </tr> + <tr> + <td><a href="http://restkit.org/api/latest/Classes/RKObjectManager.html">RKObjectManager</a></td> + <td>Captures the common patterns for communicating with a RESTful web application over HTTP using object mapping including: + <ul> + <li>Centralizing <tt>RKRequestDescriptor</tt> and <tt>RKResponseDescriptor</tt> configurations</li> + <li>Describing URL configuration with an <tt>RKRouter</tt></li> + <li>Serializing objects and sending requests with the serialized representations</li> + <li>Sending requests to load remote resources and object mapping the response bodies</li> + <li>Building multi-part form requests for objects</li> + </ul> + </td> + </tr> + <tr> + <td><a href="http://restkit.org/api/latest/Classes/RKRouter.html">RKRouter</a></td> + <td>Generates <tt>NSURL</tt> objects from a base URL and a set of <tt>RKRoute</tt> objects describing relative paths used by the application.</td> + </tr> + <tr> + <td><a href="http://restkit.org/api/latest/Classes/RKRoute.html">RKRoute</a></td> + <td>Describes a single relative path for a given object type and HTTP method, the relationship of an object, or a symbolic name.</td> + </tr> + <tr><th colspan="2" style="text-align:center;"><a href="Code/CoreData/README.md">Core Data</a></th></tr> + <tr> + <td><a href="http://restkit.org/api/latest/Classes/RKManagedObjectStore.html">RKManagedObjectStore</a></td> + <td>Encapsulates Core Data configuration including an <tt>NSManagedObjectModel</tt>, a <tt>NSPersistentStoreCoordinator</tt>, and a pair of <tt>NSManagedObjectContext</tt> objects.</td> + </tr> + <tr> + <td><a href="http://restkit.org/api/latest/Classes/RKEntityMapping.html">RKEntityMapping</a></td> + <td>Models a mapping for transforming an object representation into a <tt>NSManagedObject</tt> instance for a given <tt>NSEntityDescription</tt>.</td> + </tr> + <tr> + <td><a href="http://restkit.org/api/latest/Classes/RKConnectionDescription.html">RKConnectionDescription</a></td> + <td>Describes a mapping for establishing a relationship between Core Data entities using foreign key attributes.</td> + </tr> + <tr> + <td><a href="http://restkit.org/api/latest/Classes/RKManagedObjectRequestOperation.html">RKManagedObjectRequestOperation</a></td> + <td>An <tt>NSOperation</tt> subclass that sends an HTTP request and performs object mapping on the parsed response body to create <tt>NSManagedObject</tt> instances, establishes relationships between objects using <tt>RKConnectionDescription</tt> objects, and cleans up orphaned objects that no longer exist in the remote backend system.</td> + </tr> + <tr> + <td><a href="http://restkit.org/api/latest/Classes/RKManagedObjectImporter.html">RKManagedObjectImporter</a></td> + <td>Provides support for bulk mapping of managed objects using <tt>RKEntityMapping</tt> objects for two use cases: + <ol> + <li>Bulk importing of parsed documents into an <tt>NSPersistentStore.</tt></li> + <li>Generating a <a href="Docs for database seeding">seed database</a> for initializing an application's Core Data store with an initial data set upon installation.</li> + </ol> + </td> + </tr> + <tr><th colspan="2" style="text-align:center;"><a href="Code/Search/README.md">Search</a></th></tr> + <tr> + <td><a href="http://restkit.org/api/latest/Classes/RKSearchIndexer.html">RKSearchIndexer</a></td> + <td>Provides support for generating a full-text searchable index within Core Data for string attributes of entities within an application.</td> + </tr> + <tr> + <td><a href="http://restkit.org/api/latest/Classes/RKSearchPredicate.html">RKSearchPredicate</a></td> + <td>Generates an <tt>NSCompoundPredicate</tt> given a string of text that will search an index built with an <tt>RKSearchIndexer</tt> across any indexed entity.</td> + </tr> + <tr><th colspan="2" style="text-align:center;"><a href="Code/Testing/README.md">Testing</a></th></tr> + <tr> + <td><a href="http://restkit.org/api/latest/Classes/RKMappingTest.html">RKMappingTest</a></td> + <td>Provides support for unit testing object mapping configurations given a parsed document and an object or entity mapping. Expectations are configured in terms of expected key path mappings and/or expected transformation results.</td> + </tr> + <tr> + <td><a href="http://restkit.org/api/latest/Classes/RKTestFixture.html">RKTestFixture</a></td> + <td>Provides an interface for easily generating test fixture data for unit testing.</td> + </tr> + <tr> + <td><a href="http://restkit.org/api/latest/Classes/RKTestFactory.html">RKTestFactory</a></td> + <td>Provides support for creating objects for use in testing.</td> + </tr> +</table> + +### + +## Examples + +### Object Request +``` objective-c +// GET a single Article from /articles/1234.json and map it into an object +// JSON looks like {"article": {"title": "My Article", "author": "Blake", "body": "Very cool!!"}} +RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[Article class]]; +[mapping addAttributeMappingsFromArray:@[@"title", @"author", @"body"]]; +NSIndexSet *statusCodes = RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful); // Anything in 2xx +RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:mapping method:RKRequestMethodAny pathPattern:@"/articles/:articleID" keyPath:@"article" statusCodes:statusCodes]; + +NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://restkit.org/articles/1234.json"]]; +RKObjectRequestOperation *operation = [[RKObjectRequestOperation alloc] initWithRequest:request responseDescriptors:@[responseDescriptor]]; +[operation setCompletionBlockWithSuccess:^(RKObjectRequestOperation *operation, RKMappingResult *result) { + Article *article = [result firstObject]; + NSLog(@"Mapped the article: %@", article); +} failure:^(RKObjectRequestOperation *operation, NSError *error) { + NSLog(@"Failed with error: %@", [error localizedDescription]); +}]; +[operation start]; +``` + +### Managed Object Request +``` objective-c +// GET an Article and its Categories from /articles/888.json and map into Core Data entities +// JSON looks like {"article": {"title": "My Article", "author": "Blake", "body": "Very cool!!", "categories": [{"id": 1, "name": "Core Data"]} +NSManagedObjectModel *managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:nil]; +RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:managedObjectModel]; +NSError *error = nil; +BOOL success = RKEnsureDirectoryExistsAtPath(RKApplicationDataDirectory(), &error); +if (! success) { + RKLogError(@"Failed to create Application Data Directory at path '%@': %@", RKApplicationDataDirectory(), error); +} +NSString *path = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"Store.sqlite"]; +NSPersistentStore *persistentStore = [managedObjectStore addSQLitePersistentStoreAtPath:path fromSeedDatabaseAtPath:nil withConfiguration:nil options:nil error:&error]; +if (! persistentStore) { + RKLogError(@"Failed adding persistent store at path '%@': %@", path, error); +} +[managedObjectStore createManagedObjectContexts]; + +RKEntityMapping *categoryMapping = [RKEntityMapping mappingForEntityForName:@"Category" inManagedObjectStore:managedObjectStore]; +[categoryMapping addAttributeMappingsFromDictionary:@{ "id": "categoryID", @"name": "name" }]; +RKEntityMapping *articleMapping = [RKEntityMapping mappingForEntityForName:@"Article" inManagedObjectStore:managedObjectStore]; +[articleMapping addAttributeMappingsFromArray:@[@"title", @"author", @"body"]]; +[articleMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"categories" toKeyPath:@"categories" withMapping:categoryMapping]]; + +NSIndexSet *statusCodes = RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful); // Anything in 2xx +RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:articleMapping method:RKRequestMethodAny pathPattern:@"/articles/:articleID" keyPath:@"article" statusCodes:statusCodes]; + +NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://restkit.org/articles/888.json"]]; +RKManagedObjectRequestOperation *operation = [[RKManagedObjectRequestOperation alloc] initWithRequest:request responseDescriptors:@[responseDescriptor]]; +operation.managedObjectContext = managedObjectStore.mainQueueManagedObjectContext; +operation.managedObjectCache = managedObjectStore.managedObjectCache; +[operation setCompletionBlockWithSuccess:^(RKObjectRequestOperation *operation, RKMappingResult *result) { + Article *article = [result firstObject]; + NSLog(@"Mapped the article: %@", article); + NSLog(@"Mapped the category: %@", [article.categories anyObject]); +} failure:^(RKObjectRequestOperation *operation, NSError *error) { + NSLog(@"Failed with error: %@", [error localizedDescription]); +}]; +NSOperationQueue *operationQueue = [NSOperationQueue new]; +[operationQueue addOperation:operation]; +``` + +### Map a Client Error Response to an NSError +``` objective-c +// GET /articles/error.json returns a 422 (Unprocessable Entity) +// JSON looks like {"errors": "Some Error Has Occurred"} + +// You can map errors to any class, but `RKErrorMessage` is included for free +RKObjectMapping *errorMapping = [RKObjectMapping mappingForClass:[RKErrorMessage class]]; +// The entire value at the source key path containing the errors maps to the message +[errorMapping addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:nil toKeyPath:@"errorMessage"]]; + +NSIndexSet *statusCodes = RKStatusCodeIndexSetForClass(RKStatusCodeClassClientError); +// Any response in the 4xx status code range with an "errors" key path uses this mapping +RKResponseDescriptor *errorDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:errorMapping method:RKRequestMethodAny pathPattern:nil keyPath:@"errors" statusCodes:statusCodes]; + +NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://restkit.org/articles/error.json"]]; +RKObjectRequestOperation *operation = [[RKObjectRequestOperation alloc] initWithRequest:request responseDescriptors:@[errorDescriptor]]; +[operation setCompletionBlockWithSuccess:nil failure:^(RKObjectRequestOperation *operation, NSError *error) { + // The `description` method of the class the error is mapped to is used to construct the value of the localizedDescription + NSLog(@"Loaded this error: %@", [error localizedDescription]); + + // You can access the model object used to construct the `NSError` via the `userInfo` + RKErrorMessage *errorMessage = [[error.userInfo objectForKey:RKObjectMapperErrorObjectsKey] firstObject]; +}]; +``` + +### Centralize Configuration in an Object Manager +``` objective-c +// Set up Article and Error Response Descriptors +// Successful JSON looks like {"article": {"title": "My Article", "author": "Blake", "body": "Very cool!!"}} +RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[Article class]]; +[mapping addAttributeMappingsFromArray:@[@"title", @"author", @"body"]]; +NSIndexSet *statusCodes = RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful); // Anything in 2xx +RKResponseDescriptor *articleDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:mapping method:RKRequestMethodAny pathPattern:@"/articles" keyPath:@"article" statusCodes:statusCodes]; + +// Error JSON looks like {"errors": "Some Error Has Occurred"} +RKObjectMapping *errorMapping = [RKObjectMapping mappingForClass:[RKErrorMessage class]]; +// The entire value at the source key path containing the errors maps to the message +[errorMapping addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:nil toKeyPath:@"errorMessage"]]; +NSIndexSet *statusCodes = RKStatusCodeIndexSetForClass(RKStatusCodeClassClientError); +// Any response in the 4xx status code range with an "errors" key path uses this mapping +RKResponseDescriptor *errorDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:errorMapping method:RKRequestMethodAny pathPattern:nil keyPath:@"errors" statusCodes:statusCodes]; + +// Add our descriptors to the manager +RKObjectManager *manager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:@"http://restkit.org"]]; +[manager addResponseDescriptorsFromArray:@[ articleDescriptor, errorDescriptor ]]; + +[manager getObjectsAtPath:@"/articles/555.json" parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) { + // Handled with articleDescriptor +} failure:^(RKObjectRequestOperation *operation, NSError *error) { + // Transport error or server error handled by errorDescriptor +}]; +``` + +### Configure Core Data Integration with the Object Manager +``` objective-c +NSManagedObjectModel *managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:nil]; +RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:managedObjectModel]; +BOOL success = RKEnsureDirectoryExistsAtPath(RKApplicationDataDirectory(), &error); +if (! success) { + RKLogError(@"Failed to create Application Data Directory at path '%@': %@", RKApplicationDataDirectory(), error); +} +NSString *path = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"Store.sqlite"]; +NSPersistentStore *persistentStore = [managedObjectStore addSQLitePersistentStoreAtPath:path fromSeedDatabaseAtPath:nil withConfiguration:nil options:nil error:&error]; +if (! persistentStore) { + RKLogError(@"Failed adding persistent store at path '%@': %@", path, error); +} +[managedObjectStore createManagedObjectContexts]; + +RKObjectManager *manager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:@"http://restkit.org"]]; +manager.managedObjectStore = managedObjectStore; +``` + +### Load a Collection of Objects at a Path +``` objective-c +RKObjectManager *manager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:@"http://restkit.org"]]; +[manager getObjectsAtPath:@"/articles" parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) { +} failure:^(RKObjectRequestOperation *operation, NSError *error) { +}]; +``` + +### Manage a Queue of Object Request Operations +``` objective-c +RKObjectManager *manager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:@"http://restkit.org"]]; + +NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://restkit.org/articles/1234.json"]]; +RKObjectRequestOperation *operation = [[RKObjectRequestOperation alloc] initWithRequest:request responseDescriptors:@[responseDescriptor]]; + +[manager enqueueObjectRequestOperation:operation]; +[manager cancelAllObjectRequestOperationsWithMethod:RKRequestMethodANY matchingPathPattern:@"/articles/:articleID\\.json"]; +``` + +### POST, PATCH, and DELETE an Object +``` objective-c +RKObjectMapping *responseMapping = [RKObjectMapping mappingForClass:[Article class]]; +[responseMapping addAttributeMappingsFromArray:@[@"title", @"author", @"body"]]; +NSIndexSet *statusCodes = RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful); // Anything in 2xx +RKResponseDescriptor *articleDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:responseMapping method:RKRequestMethodAny pathPattern:@"/articles" keyPath:@"article" statusCodes:statusCodes]; + +RKObjectMapping *requestMapping = [RKObjectMapping requestMapping]; // objectClass == NSMutableDictionary +[requestMapping addAttributeMappingsFromArray:@[@"title", @"author", @"body"]]; + +// For any object of class Article, serialize into an NSMutableDictionary using the given mapping and nest +// under the 'article' key path +RKRequestDescriptor *requestDescriptor = [RKRequestDescriptor requestDescriptorWithMapping:requestMapping objectClass:[Article class] rootKeyPath:@"article" method:RKRequestMethodAny]; + +RKObjectManager *manager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:@"http://restkit.org"]]; +[manager addRequestDescriptor:requestDescriptor]; +[manager addResponseDescriptor:articleDescriptor]; + +Article *article = [Article new]; +article.title = @"Introduction to RestKit"; +article.body = @"This is some text."; +article.author = @"Blake"; + +// POST to create +[manager postObject:article path:@"/articles" parameters:nil success:nil failure:nil]; + +// PATCH to update +article.body = @"New Body"; +[manager patchObject:article path:@"/articles/1234" parameters:nil success:nil failure:nil]; + +// DELETE to destroy +[manager deleteObject:article path:@"/articles/1234" parameters:nil success:nil failure:nil]; +``` + +### Configure Logging +``` objective-c +// Log all HTTP traffic with request and response bodies +RKLogConfigureByName("RestKit/Network", RKLogLevelTrace); + +// Log debugging info about Core Data +RKLogConfigureByName("RestKit/CoreData", RKLogLevelDebug); + +// Raise logging for a block +RKLogWithLevelWhileExecutingBlock(RKLogLevelTrace, ^{ + // Do something that generates logs +}); +``` + +### Configure Routing +``` objective-c +RKObjectManager *manager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:@"http://restkit.org"]]; + +// Class Routing +[manager.router.routeSet addRoute:[RKRoute routeWithClass:[GGSegment class] pathPattern:@"/segments/:segmentID\\.json" method:RKRequestMethodGET]]; + +// Relationship Routing +[manager.router.routeSet addRoute:[RKRoute routeWithRelationshipName:@"amenities" objectClass:[GGAirport class] pathPattern:@"/airports/:airportID/amenities.json" method:RKRequestMethodGET]]; + +// Named Routes +[manager.router.routeSet addRoute:[RKRoute routeWithName:@"thumbs_down_review" resourcePathPattern:@"/reviews/:reviewID/thumbs_down" method:RKRequestMethodPOST]]; +``` + +### POST an Object with a File Attachment +``` objective-c +Article *article = [Article new]; +UIImage *image = [UIImage imageNamed:@"some_image.png"]; + +// Serialize the Article attributes then attach a file +NSMutableURLRequest *request = [[RKObjectManager sharedManager] multipartFormRequestWithObject:article method:RKRequestMethodPOST path:nil parameters:nil constructingBodyWithBlock:^(id<AFMultipartFormData> formData) { + [formData appendPartWithFileData:UIImagePNGRepresentation(image) + name:@"article[image]" + fileName:@"photo.png" + mimeType:@"image/png"]; +}]; + +RKObjectRequestOperation *operation = [[RKObjectManager sharedManager] objectRequestOperationWithRequest:request success:nil failure:nil]; +[[RKObjectManager sharedManager] enqueueObjectRequestOperation:operation]; // NOTE: Must be enqueued rather than started +``` + +### Enqueue a Batch of Object Request Operations +``` objective-c + +RKObjectManager *manager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:@"http://restkit.org"]]; + +Airport *jfk = [Airport new]; +jfk.code = @"jfk"; +Airport *lga = [Airport new]; +lga.code = @"lga"; +Airport *rdu = [Airport new]; +rdu.code = @"rdu"; + +// Enqueue a GET for '/airports/jfk/weather', '/airports/lga/weather', '/airports/rdu/weather' +RKRoute *route = [RKRoute routeWithName:@"airport_weather" resourcePathPattern:@"/airports/:code/weather" method:RKRequestMethodGET]; + +[manager enqueueBatchOfObjectRequestOperationsWithRoute:route + objects:@[ jfk, lga, rdu] + progress:^(NSUInteger numberOfFinishedOperations, NSUInteger totalNumberOfOperations) { + NSLog(@"Finished %d operations", numberOfFinishedOperations); + } completion:^ (NSArray *operations) { + NSLog(@"All Weather Reports Loaded!"); + }]; +``` + +### Generate a Seed Database +``` objective-c +NSManagedObjectModel *managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:nil]; +RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:managedObjectModel]; +NSError *error = nil; +BOOL success = RKEnsureDirectoryExistsAtPath(RKApplicationDataDirectory(), &error); +if (! success) { + RKLogError(@"Failed to create Application Data Directory at path '%@': %@", RKApplicationDataDirectory(), error); +} +NSString *path = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"Store.sqlite"]; +NSPersistentStore *persistentStore = [managedObjectStore addSQLitePersistentStoreAtPath:path fromSeedDatabaseAtPath:nil withConfiguration:nil options:nil error:&error]; +if (! persistentStore) { + RKLogError(@"Failed adding persistent store at path '%@': %@", path, error); +} +[managedObjectStore createManagedObjectContexts]; + +RKEntityMapping *articleMapping = [RKEntityMapping mappingForEntityForName:@"Article" inManagedObjectStore:managedObjectStore]; +[articleMapping addAttributeMappingsFromArray:@[@"title", @"author", @"body"]]; + +NSString *seedPath = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"MySeedDatabase.sqlite"]; +RKManagedObjectImporter *importer = [[RKManagedObjectImporter alloc] initWithManagedObjectModel:managedObjectStore.managedObjectModel storePath:seedPath]; + +// Import the files "articles.json" from the Main Bundle using our RKEntityMapping +// JSON looks like {"articles": [ {"title": "Article 1", "body": "Text", "author": "Blake" ]} +NSError *error; +NSBundle *mainBundle = [NSBundle mainBundle]; +[importer importObjectsFromItemAtPath:[mainBundle pathForResource:@"articles" ofType:@"json"] + withMapping:articleMapping + keyPath:@"articles" + error:&error]; + +BOOL success = [importer finishImporting:&error]; +if (success) { + [importer logSeedingInfo]; +} +``` + +### Index and Search an Entity +``` objective-c +NSManagedObjectModel *managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:nil]; +RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:managedObjectModel]; +NSError *error = nil; +BOOL success = RKEnsureDirectoryExistsAtPath(RKApplicationDataDirectory(), &error); +if (! success) { + RKLogError(@"Failed to create Application Data Directory at path '%@': %@", RKApplicationDataDirectory(), error); +} +NSString *path = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"Store.sqlite"]; +NSPersistentStore *persistentStore = [managedObjectStore addSQLitePersistentStoreAtPath:path fromSeedDatabaseAtPath:nil withConfiguration:nil options:nil error:&error]; +if (! persistentStore) { + RKLogError(@"Failed adding persistent store at path '%@': %@", path, error); +} +[managedObjectStore createManagedObjectContexts]; +[managedObjectStore addSearchIndexingToEntityForName:@"Article" onAttributes:@[ @"title", @"body" ]]; +[managedObjectStore addInMemoryPersistentStore:nil]; +[managedObjectStore createManagedObjectContexts]; +[managedObjectStore startIndexingPersistentStoreManagedObjectContext]; + +Article *article1 = [NSEntityDescription insertNewObjectForEntityForName:@"Article" inManagedObjectContext:managedObjectStore.mainQueueManagedObjectContext]; +article1.title = @"First Article"; +article1.body = "This should match search"; + +Article *article2 = [NSEntityDescription insertNewObjectForEntityForName:@"Article" inManagedObjectContext:managedObjectStore.mainQueueManagedObjectContext]; +article2.title = @"Second Article"; +article2.body = "Does not"; + +BOOL success = [managedObjectStore.mainQueueManagedObjectContext saveToPersistentStore:nil]; + +RKSearchPredicate *predicate = [RKSearchPredicate searchPredicateWithText:@"Match" type:NSAndPredicateType]; +NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Article"]; +fetchRequest.predicate = predicate; + +// Contains article1 due to body text containing 'match' +NSArray *matches = [managedObjectStore.mainQueueManagedObjectContext executeFetchRequest:fetchRequest error:nil]; +NSLog(@"Found the matching articles: %@", matches); +``` + +### Unit Test a Mapping +``` objective-c +// JSON looks like {"article": {"title": "My Article", "author": "Blake", "body": "Very cool!!"}} +RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[Article class]]; +[mapping addAttributeMappingsFromArray:@[@"title", @"author", @"body"]]; + +NSDictionary *article = @{ @"article": @{ @"title": @"My Title", @"body": @"The article body", @"author": @"Blake" } }; +RKMappingTest *mappingTest = [[RKMappingTest alloc] initWithMapping:mapping sourceObject:article destinationObject:nil]; + +[mappingTest expectMappingFromKeyPath:@"title" toKeyPath:@"title" value:@"My Title"]; +[mappingTest performMapping]; +[mappingTest verify]; +``` + +## Requirements + +RestKit requires [iOS 5.1.1](http://developer.apple.com/library/ios/#releasenotes/General/WhatsNewIniPhoneOS/Articles/iOS5.html#//apple_ref/doc/uid/TP30915195-SW1) and above or [Mac OS X 10.7](http://developer.apple.com/library/mac/#releasenotes/MacOSX/WhatsNewInOSX/Articles/MacOSX10_7.html#//apple_ref/doc/uid/TP40010355-SW5) and above. + +Several third-party open source libraries are used within RestKit, including: + +1. [AFNetworking](https://github.com/AFNetworking/AFNetworking) - Networking Support +2. [LibComponentLogging](http://0xc0.de/LibComponentLogging) - Logging Support +3. [SOCKit](https://github.com/NimbusKit/sockit) - String <-> Object Coding +4. [iso8601parser](http://boredzo.org/iso8601parser/) - Support for parsing and generating ISO-8601 dates + +The following Cocoa frameworks must be linked into the application target for proper compilation: + +1. **CFNetwork.framework** on iOS +1. **CoreData.framework** +1. **Security.framework** +1. **MobileCoreServices.framework** on iOS or **CoreServices.framework** on OS X + +And the following linker flags must be set: + +1. **-ObjC** +1. **-all_load** + +### ARC + +As of [version 0.20.0](https://github.com/RestKit/RestKit/wiki/Restkit-0.20.0), RestKit has migrated the entire codebase to ARC. + +If you are including the RestKit sources directly into a project that does not yet use [Automatic Reference Counting](http://clang.llvm.org/docs/AutomaticReferenceCounting.html), you will need to set the `-fobjc-arc` compiler flag on all of the RestKit source files. To do this in Xcode, go to your active target and select the "Build Phases" tab. Now select all RestKit source files, press Enter, insert `-fobjc-arc` and then "Done" to enable ARC for RestKit. + +### Serialization Formats + +RestKit provides a pluggable interface for handling arbitrary serialization formats via the [`RKSerialization`](http://restkit.org/api/latest/Classes/RKSerialization.html) protocol and the [`RKMIMETypeSerialization`](http://restkit.org/api/latest/Classes/RKMIMETypeSerialization.html) class. Out of the box, RestKit supports handling the [JSON](http://www.json.org/) format for serializing and deserializing object representations via the [`NSJSONSerialization`](http://developer.apple.com/library/mac/#documentation/Foundation/Reference/NSJSONSerialization_Class/Reference/Reference.html) class. + +#### Additional Serializations + +Support for additional formats and alternate serialization backends is provided via external modules that can be added to the project. Currently the following serialization implementations are available for use: + +* JSONKit +* SBJSON +* YAJL +* NextiveJson +* XMLReader + XMLWriter + +## Installation + +The recommended approach for installing RestKit is via the [CocoaPods](http://cocoapods.org/) package manager, as it provides flexible dependency management and dead simple installation. For best results, it is recommended that you install via CocoaPods **>= 0.19.1** using Git **>= 1.8.0** installed via Homebrew. + +### via CocoaPods + +Install CocoaPods if not already available: + +``` bash +$ [sudo] gem install cocoapods +$ pod setup +``` + +Change to the directory of your Xcode project, and Create and Edit your Podfile and add RestKit: + +``` bash +$ cd /path/to/MyProject +$ touch Podfile +$ edit Podfile +platform :ios, '5.0' +# Or platform :osx, '10.7' +pod 'RestKit', '~> 0.24.0' + +# Testing and Search are optional components +pod 'RestKit/Testing', '~> 0.24.0' +pod 'RestKit/Search', '~> 0.24.0' +``` + +Install into your project: + +``` bash +$ pod install +``` + +Open your project in Xcode from the .xcworkspace file (not the usual project file) + +``` bash +$ open MyProject.xcworkspace +``` + +Please note that if your installation fails, it may be because you are installing with a version of Git lower than CocoaPods is expecting. Please ensure that you are running Git **>= 1.8.0** by executing `git --version`. You can get a full picture of the installation details by executing `pod install --verbose`. + +### From a Release Package or as a Git submodule + +Detailed installation instructions are available in the [Visual Install Guide](https://github.com/RestKit/RestKit/wiki/Installing-RestKit-v0.20.x-as-a-Git-Submodule) on the Wiki. + +## License + +RestKit is licensed under the terms of the [Apache License, version 2.0](http://www.apache.org/licenses/LICENSE-2.0.html). Please see the [LICENSE](LICENSE) file for full details. + +## Credits + +RestKit is brought to you by [Blake Watters](http://twitter.com/blakewatters) and the RestKit team. + +Support is provided by the following organizations: + +* [GateGuru](http://www.gateguruapp.com/) +* [Two Toasters](http://www.twotoasters.com/) diff --git a/Pods/RestKit/Vendor/LibComponentLogging/Core/lcl_RK.h b/Pods/RestKit/Vendor/LibComponentLogging/Core/lcl_RK.h new file mode 100644 index 0000000..25ff99d --- /dev/null +++ b/Pods/RestKit/Vendor/LibComponentLogging/Core/lcl_RK.h @@ -0,0 +1,390 @@ +// +// +// lcl_RK.h -- LibComponentLogging, embedded, RestKit/RK +// +// +// Copyright (c) 2008-2012 Arne Harren <ah@0xc0.de> +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef __RKLCL_H__ +#define __RKLCL_H__ + +#define _RKLCL_VERSION_MAJOR 1 +#define _RKLCL_VERSION_MINOR 3 +#define _RKLCL_VERSION_BUILD 1 +#define _RKLCL_VERSION_SUFFIX "" + +#import "lcl_config_components_RK.h" + +// +// lcl -- LibComponentLogging, embedded, RestKit/RK +// +// LibComponentLogging is a logging library for Objective-C applications +// with the following characteristics: +// +// - Log levels +// The library provides log levels for distinguishing between error messages, +// informational messages, and fine-grained trace messages for debugging. +// +// - Log components +// The library provides log components for identifying different parts of an +// application. A log component contains a unique identifier, a short name +// which is used as a header in a log message, and a full name which can be +// used in a user interface. +// +// - Active log level per log component +// At runtime, the library provides an active log level for each log +// component in order to enable/disable logging for certain parts of an +// application. +// +// - Grouping of log components +// Log components which have the same name prefix form a group of log +// components and logging can be enabled/disabled for the whole group with +// a single command. +// +// - Low runtime-overhead when logging is disabled +// Logging is based on a log macro which checks the active log level before +// constructing the log message and before evaluating log message arguments. +// +// - Code completion support +// The library provides symbols for log components and log levels which work +// with Xcode's code completion. All symbols, e.g. values or functions, which +// are relevant when using the logging library in an application, are prefixed +// with 'RKlcl_'. Internal symbols, which are needed when working with meta +// data, when defining log components, or when writing a logging back-end, are +// prefixed with '_RKlcl_'. Internal symbols, which are only used by the logging +// library itself, are prefixed with '__RKlcl_'. +// +// - Meta data +// The library provides public data structures which contain information about +// log levels and log components, e.g. headers and names. +// +// - Pluggable loggers +// The library does not contain a concrete logger, but provides a simple +// delegation mechanism for plugging-in a concrete logger based on the +// application's requirements, e.g. a logger which writes to the system log, +// or a logger which writes to a log file. The concrete logger is configured +// at build-time. +// +// Note: If the preprocessor symbol _RKLCL_NO_LOGGING is defined, the log macro +// will be defined to an empty effect. +// + + +#import <Foundation/Foundation.h> + + +// Use C linkage. +#ifdef __cplusplus +extern "C" { +#endif + + +// +// Log levels. +// + + +// Log levels, prefixed with 'RKlcl_v'. +enum _RKlcl_enum_level_t { + RKlcl_vOff = 0, + + RKlcl_vCritical, // critical situation + RKlcl_vError, // error situation + RKlcl_vWarning, // warning + RKlcl_vInfo, // informational message + RKlcl_vDebug, // coarse-grained debugging information + RKlcl_vTrace, // fine-grained debugging information + + _RKlcl_level_t_count, + _RKlcl_level_t_first = 0, + _RKlcl_level_t_last = _RKlcl_level_t_count-1 +}; + +// Log level type. +typedef uint32_t _RKlcl_level_t; +typedef uint8_t _RKlcl_level_narrow_t; + + +// +// Log components. +// + + +// Log components, prefixed with 'RKlcl_c'. +enum _RKlcl_enum_component_t { +# define _RKlcl_component(_identifier, _header, _name) \ + RKlcl_c##_identifier, \ + __RKlcl_log_symbol_RKlcl_c##_identifier = RKlcl_c##_identifier, + RKLCLComponentDefinitions +# undef _RKlcl_component + + _RKlcl_component_t_count, + _RKlcl_component_t_first = 0, + _RKlcl_component_t_last = _RKlcl_component_t_count-1 +}; + +// Log component type. +typedef uint32_t _RKlcl_component_t; + + +// +// Functions and macros. +// + +#ifndef _RKLCL_NO_IGNORE_WARNINGS +# ifdef __clang__ + // Ignore some warnings about variadic macros when using '-Weverything'. +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wunknown-pragmas" +# pragma clang diagnostic ignored "-Wvariadic-macros" +# pragma clang diagnostic ignored "-Wpedantic" +# endif +#endif + +// RKlcl_log(<component>, <level>, <format>[, <arg1>[, <arg2>[, ...]]]) +// +// <component>: a log component with prefix 'RKlcl_c' +// <level> : a log level with prefix 'RKlcl_v' +// <format> : a format string of type NSString (may include %@) +// <arg..> : optional arguments required by the format string +// +// Logs a message for the given log component at the given log level if the +// log level is active for the log component. +// +// The actual logging is done by _RKlcl_logger which must be defined by a concrete +// logging back-end. _RKlcl_logger has the same signature as RKlcl_log. +// +#ifdef _RKLCL_NO_LOGGING +# define RKlcl_log(_component, _level, _format, ...) \ + do { \ + } while (0) +#else +# define RKlcl_log(_component, _level, _format, ...) \ + do { \ + if (((_RKlcl_component_level[(__RKlcl_log_symbol(_component))]) >= \ + (__RKlcl_log_symbol(_level))) \ + ) { \ + _RKlcl_logger(_component, \ + _level, \ + _format, \ + ##__VA_ARGS__); \ + } \ + } while (0) +#endif + +// RKlcl_log_if(<component>, <level>, <predicate>, <format>[, <arg1>[, ...]]) +// +// <component>: a log component with prefix 'RKlcl_c' +// <level> : a log level with prefix 'RKlcl_v' +// <predicate>: a predicate for conditional logging +// <format> : a format string of type NSString (may include %@) +// <arg..> : optional arguments required by the format string +// +// Logs a message for the given log component at the given log level if the +// log level is active for the log component and if the predicate evaluates +// to true. +// +// The predicate is only evaluated if the given log level is active. +// +// The actual logging is done by _RKlcl_logger which must be defined by a concrete +// logging back-end. _RKlcl_logger has the same signature as RKlcl_log. +// +#ifdef _RKLCL_NO_LOGGING +# define RKlcl_log_if(_component, _level, _predicate, _format, ...) \ + do { \ + } while (0) +#else +# define RKlcl_log_if(_component, _level, _predicate, _format, ...) \ + do { \ + if (((_RKlcl_component_level[(__RKlcl_log_symbol(_component))]) >= \ + (__RKlcl_log_symbol(_level))) \ + && \ + (_predicate) \ + ) { \ + _RKlcl_logger(_component, \ + _level, \ + _format, \ + ##__VA_ARGS__); \ + } \ + } while (0) +#endif + +#ifndef _RKLCL_NO_IGNORE_WARNINGS +# ifdef __clang__ +# pragma clang diagnostic pop +# endif +#endif + +// RKlcl_configure_by_component(<component>, <level>) +// +// <component>: a log component with prefix 'RKlcl_c' +// <level> : a log level with prefix 'RKlcl_v' +// +// Configures the given log level for the given log component. +// Returns the number of configured log components, or 0 on failure. +// +uint32_t RKlcl_configure_by_component(_RKlcl_component_t component, _RKlcl_level_t level); + +// RKlcl_configure_by_identifier(<identifier>, <level>) +// +// <identifier>: a log component's identifier with optional '*' wildcard suffix +// <level> : a log level with prefix 'RKlcl_v' +// +// Configures the given log level for the given log component(s). +// Returns the number of configured log components, or 0 on failure. +// +uint32_t RKlcl_configure_by_identifier(const char *identifier, _RKlcl_level_t level); + +// RKlcl_configure_by_header(<header>, <level>) +// +// <header> : a log component's header with optional '*' wildcard suffix +// <level> : a log level with prefix 'RKlcl_v' +// +// Configures the given log level for the given log component(s). +// Returns the number of configured log components, or 0 on failure. +// +uint32_t RKlcl_configure_by_header(const char *header, _RKlcl_level_t level); + +// RKlcl_configure_by_name(<name>, <level>) +// +// <name> : a log component's name with optional '*' wildcard suffix +// <level> : a log level with prefix 'RKlcl_v' +// +// Configures the given log level for the given log component(s). +// Returns the number of configured log components, or 0 on failure. +// +uint32_t RKlcl_configure_by_name(const char *name, _RKlcl_level_t level); + + +// +// Internals. +// + + +// Active log levels, indexed by log component. +extern _RKlcl_level_narrow_t _RKlcl_component_level[_RKlcl_component_t_count]; + +// Log component identifiers, indexed by log component. +extern const char * const _RKlcl_component_identifier[_RKlcl_component_t_count]; + +// Log component headers, indexed by log component. +extern const char * const _RKlcl_component_header[_RKlcl_component_t_count]; + +// Log component names, indexed by log component. +extern const char * const _RKlcl_component_name[_RKlcl_component_t_count]; + +// Log level headers, indexed by log level. +extern const char * const _RKlcl_level_header[_RKlcl_level_t_count]; // full header +extern const char * const _RKlcl_level_header_1[_RKlcl_level_t_count]; // header with 1 character +extern const char * const _RKlcl_level_header_3[_RKlcl_level_t_count]; // header with 3 characters + +// Log level names, indexed by log level. +extern const char * const _RKlcl_level_name[_RKlcl_level_t_count]; + +// Version. +extern const char * const _RKlcl_version; + +// Log level symbols used by RKlcl_log, prefixed with '__RKlcl_log_symbol_RKlcl_v'. +enum { + __RKlcl_log_symbol_RKlcl_vCritical = RKlcl_vCritical, + __RKlcl_log_symbol_RKlcl_vError = RKlcl_vError, + __RKlcl_log_symbol_RKlcl_vWarning = RKlcl_vWarning, + __RKlcl_log_symbol_RKlcl_vInfo = RKlcl_vInfo, + __RKlcl_log_symbol_RKlcl_vDebug = RKlcl_vDebug, + __RKlcl_log_symbol_RKlcl_vTrace = RKlcl_vTrace +}; + +// Macro for appending the '__RKlcl_log_symbol_' prefix to a given symbol. +#define __RKlcl_log_symbol(_symbol) \ + __RKlcl_log_symbol_##_symbol + + +// End C linkage. +#ifdef __cplusplus +} +#endif + + +// Include logging back-end and definition of _RKlcl_logger. +#import "lcl_config_logger_RK.h" + + +// For simple configurations where 'lcl_config_logger_RK.h' is empty, define a +// default NSLog()-based _RKlcl_logger here. +#ifndef _RKlcl_logger + +// ARC/non-ARC autorelease pool +#define _RKlcl_logger_autoreleasepool_arc 0 +#if defined(__has_feature) +# if __has_feature(objc_arc) +# undef _RKlcl_logger_autoreleasepool_arc +# define _RKlcl_logger_autoreleasepool_arc 1 +# endif +#endif +#if _RKlcl_logger_autoreleasepool_arc +# define _RKlcl_logger_autoreleasepool_begin \ + @autoreleasepool { +# define _RKlcl_logger_autoreleasepool_end \ + } +#else +# define _RKlcl_logger_autoreleasepool_begin \ + NSAutoreleasePool *_RKlcl_logger_autoreleasepool = [[NSAutoreleasePool alloc] init]; +# define _RKlcl_logger_autoreleasepool_end \ + [_RKlcl_logger_autoreleasepool release]; +#endif + +#ifndef _RKLCL_NO_IGNORE_WARNINGS +# ifdef __clang__ + // Ignore some warnings about variadic macros when using '-Weverything'. +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wunknown-pragmas" +# pragma clang diagnostic ignored "-Wvariadic-macros" +# pragma clang diagnostic ignored "-Wpedantic" +# endif +#endif + +// A simple default logger, which redirects to NSLog(). +#define _RKlcl_logger(_component, _level, _format, ...) { \ + _RKlcl_logger_autoreleasepool_begin \ + NSLog(@"%s %s:%@:%d " _format, \ + _RKlcl_level_header_1[_level], \ + _RKlcl_component_header[_component], \ + [@__FILE__ lastPathComponent], \ + __LINE__, \ + ## __VA_ARGS__); \ + _RKlcl_logger_autoreleasepool_end \ +} + +#ifndef _RKLCL_NO_IGNORE_WARNINGS +# ifdef __clang__ +# pragma clang diagnostic pop +# endif +#endif + +#endif + + +// Include extensions. +#import "lcl_config_extensions_RK.h" + + +#endif // __RKLCL_H__ + diff --git a/Pods/RestKit/Vendor/LibComponentLogging/Core/lcl_RK.m b/Pods/RestKit/Vendor/LibComponentLogging/Core/lcl_RK.m new file mode 100644 index 0000000..c860296 --- /dev/null +++ b/Pods/RestKit/Vendor/LibComponentLogging/Core/lcl_RK.m @@ -0,0 +1,176 @@ +// +// +// lcl_RK.m -- LibComponentLogging, embedded, RestKit/RK +// +// +// Copyright (c) 2008-2012 Arne Harren <ah@0xc0.de> +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "lcl_RK.h" +#include <string.h> + + +// Active log levels, indexed by log component. +_RKlcl_level_narrow_t _RKlcl_component_level[_RKlcl_component_t_count]; + +// Log component identifiers, indexed by log component. +const char * const _RKlcl_component_identifier[] = { +# define _RKlcl_component(_identifier, _header, _name) \ + #_identifier, + RKLCLComponentDefinitions +# undef _RKlcl_component +}; + +// Log component headers, indexed by log component. +const char * const _RKlcl_component_header[] = { +# define _RKlcl_component(_identifier, _header, _name) \ + _header, + RKLCLComponentDefinitions +# undef _RKlcl_component +}; + +// Log component names, indexed by log component. +const char * const _RKlcl_component_name[] = { +# define _RKlcl_component(_identifier, _header, _name) \ + _name, + RKLCLComponentDefinitions +# undef _RKlcl_component +}; + +// Log level headers, indexed by log level. +const char * const _RKlcl_level_header[] = { + "-", + "CRITICAL", + "ERROR", + "WARNING", + "INFO", + "DEBUG", + "TRACE" +}; +const char * const _RKlcl_level_header_1[] = { + "-", + "C", + "E", + "W", + "I", + "D", + "T" +}; +const char * const _RKlcl_level_header_3[] = { + "---", + "CRI", + "ERR", + "WRN", + "INF", + "DBG", + "TRC" +}; + +// Log level names, indexed by log level. +const char * const _RKlcl_level_name[] = { + "Off", + "Critical", + "Error", + "Warning", + "Info", + "Debug", + "Trace" +}; + +// Version. +#define __RKlcl_version_to_string( _text) __RKlcl_version_to_string0(_text) +#define __RKlcl_version_to_string0(_text) #_text +const char * const _RKlcl_version = __RKlcl_version_to_string(_RKLCL_VERSION_MAJOR) + "." __RKlcl_version_to_string(_RKLCL_VERSION_MINOR) + "." __RKlcl_version_to_string(_RKLCL_VERSION_BUILD) + "" _RKLCL_VERSION_SUFFIX; + +// Configures the given log level for the given log component. +uint32_t RKlcl_configure_by_component(_RKlcl_component_t component, _RKlcl_level_t level) { + // unsupported level, clip to last level + if (level > _RKlcl_level_t_last) { + level = _RKlcl_level_t_last; + } + + // configure the component + if (component <= _RKlcl_component_t_last) { + _RKlcl_component_level[component] = level; + return 1; + } + + return 0; +} + +// Configures the given log level for the given log component(s). +static uint32_t _RKlcl_configure_by_text(uint32_t count, const char * const *texts, + _RKlcl_level_narrow_t *levels, const char *text, + _RKlcl_level_t level) { + // no text given, quit + if (text == NULL || text[0] == '\0') { + return 0; + } + + // unsupported level, clip to last level + if (level > _RKlcl_level_t_last) { + level = _RKlcl_level_t_last; + } + + // configure the components + uint32_t num_configured = 0; + size_t text_len = strlen(text); + if (text[text_len-1] == '*') { + // text ends with '*', wildcard suffix was specified + text_len--; + for (uint32_t c = 0; c < count; c++) { + if (strncmp(text, texts[c], text_len) == 0) { + levels[c] = level; + num_configured++; + } + } + } else { + // no wildcard suffix was specified + for (uint32_t c = 0; c < count; c++) { + if (strcmp(text, texts[c]) == 0) { + levels[c] = level; + num_configured++; + } + } + } + return num_configured; +} + +// Configures the given log level for the given log component(s) by identifier. +uint32_t RKlcl_configure_by_identifier(const char *identifier, _RKlcl_level_t level) { + return _RKlcl_configure_by_text(_RKlcl_component_t_count, _RKlcl_component_identifier, + _RKlcl_component_level, identifier, level); +} + +// Configures the given log level for the given log component(s) by header. +uint32_t RKlcl_configure_by_header(const char *header, _RKlcl_level_t level) { + return _RKlcl_configure_by_text(_RKlcl_component_t_count, _RKlcl_component_header, + _RKlcl_component_level, header, level); +} + +// Configures the given log level for the given log component(s) by name. +uint32_t RKlcl_configure_by_name(const char *name, _RKlcl_level_t level) { + return _RKlcl_configure_by_text(_RKlcl_component_t_count, _RKlcl_component_name, + _RKlcl_component_level, name, level); +} + diff --git a/Pods/SOCKit/LICENSE b/Pods/SOCKit/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/Pods/SOCKit/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Pods/SOCKit/README.mdown b/Pods/SOCKit/README.mdown new file mode 100644 index 0000000..8f66367 --- /dev/null +++ b/Pods/SOCKit/README.mdown @@ -0,0 +1,94 @@ +SOCKit +====== + +String <-> Object Coding for Objective-C. Rhymes with "socket". + +With SOCKit and [SOCPattern][] you can easily transform objects into strings and vice versa. + +### Two examples, cuz devs love examples. + +```obj-c +SOCPattern* pattern = [SOCPattern patternWithString:@"api.github.com/users/:username/gists"]; +[pattern stringFromObject:githubUser]; +> @"api.github.com/users/jverkoey/gists" +``` + +```obj-c +SOCPattern* pattern = [SOCPattern patternWithString:@"github.com/:username"]; +[pattern performSelector:@selector(initWithUsername:) onObject:[GithubUser class] sourceString:@"github.com/jverkoey"]; +> <GithubUser> username = jverkoey +``` + +### Hey, this is really similar to defining routes in Rails. + +Damn straight it is. + +### And isn't this kind of like Three20's navigator? + +Except hella better. It's also entirely incompatible with Three20 routes. This kinda blows if +you've already invested a ton of energy into Three20's routing tech, but here are a few reasons +why SOCKit is better: + +1. *Selectors are not defined in the pattern*. The fact that Three20 requires that you define + selectors in the pattern is scary as hell: rename a method in one of your controllers and + your URL routing will silently break. No warnings, just broke. With SOCKit you define the + selectors using @selector notation and SOCKit infers the parameters from the pattern definition. + This way you can depend on the compiler to fire a warning if the selector isn't defined anywhere. +2. *Parameters are encoded using true KVC*. You now have full access to [KVC collection operators]. +3. *SOCKit is fully unit tested and documented*. Not much more to be said here. + +Here's a quick breakdown of the differences between Three20 and SOCKit, if SOCKit were used as +the backend for Three20's URL routing. + +``` +Three20: [map from:@"twitter://tweet/(initWithTweetId:)" toViewController:[TweetController class]]; +SOCKit: [map from:@"twitter://tweet/:id" toViewController:[TweetController class] selector:@selector(initWithTweetId:)]; + +Three20: [map from:[Tweet class] name:@"thread" toURL:@"twitter://tweet/(id)/thread"]; +SOCKit: [map from:[Tweet class] name:@"thread" toURL:@"twitter://tweet/:id/thread"]; +``` + +## Where it's being used + +SOCKit is a sibling project to [Nimbus][], a light-weight and modular framework that makes it +easy to blaze a trail with your iOS apps. Nimbus will soon be using SOCKit in a re-envisioning +of Three20's navigator. + +Users of RESTKit will notice that SOCKit provides similar functionality to RESTKit's +[RKMakePathWithObject][]. In fact, both `RKMakePathWithObject` and the underlying `RKPathMatcher` +class rely on SOCKit behind the scenes. + +## Adding SOCKit to your project + +This lightweight library is built to be a dead-simple airdrop directly into your project. Contained +in SOCKit.h and SOCKit.m is all of the functionality you will need in order to start mapping +Strings <-> Objects. To start using SOCKit, simply download or `git checkout` the SOCKit repo +and drag SOCKit.h and SOCKit.m to your project's source tree. `#import "SOCKit.h"` where you want +to use SOCKit and start pumping out some mad String <-> Object coding. + +## Some cool things + +When coding objects into strings you define parameters by prefixing the property name with a colon. +So if you have a Tweet object with a `tweetId` property, the pattern parameter name would look like +`:tweetId`. Simple enough. + +But now let's say you have a Tweet object that contains a reference to a TwitterUser object via +the `user` property, and that TwitterUser object has a `username` property. Check this out: +`:user.username`. If this was one of my tweets and I encoded the Tweet object using a SOCKit +pattern the resulting string would be `@"featherless"`. KVC rocks. + +## Learning more + +In-depth documentation can be found in the [SOCKit.h][SOCPattern] header file. + +## Contributing + +If you find a bug in SOCKit please file an issue on the Github [SOCKit issue tracker][]. Even +better: if you have a solution for the bug then fork the project and make a pull request. + +[SOCKit issue tracker]: https://github.com/jverkoey/sockit/issues +[SOCPattern]: https://github.com/jverkoey/sockit/blob/master/SOCKit.h +[KVC collection operators]: http://developer.apple.com/library/ios/#documentation/cocoa/conceptual/KeyValueCoding/Articles/CollectionOperators.html#//apple_ref/doc/uid/20002176-BAJEAIEE +[Nimbus]: http://jverkoey.github.com/nimbus +[RESTKit]: https://github.com/RestKit/RestKit +[RKMakePathWithObject]: https://github.com/RestKit/RestKit/blob/master/Code/Network/RKClient.m#L37 \ No newline at end of file diff --git a/Pods/SOCKit/SOCKit.h b/Pods/SOCKit/SOCKit.h new file mode 100644 index 0000000..57fcf44 --- /dev/null +++ b/Pods/SOCKit/SOCKit.h @@ -0,0 +1,214 @@ +// +// Copyright 2011-2012 Jeff Verkoeyen +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import <Foundation/Foundation.h> + +/** + * String <-> Object Coding. + * + * Code information from strings into objects and vice versa. + * + * A pattern is a string with parameter names prefixed by colons (":"). + * An example of a pattern string with one parameter named :username is: + * api.github.com/users/:username/gists + * + * Patterns, once created, can be used to efficiently turn objects into strings and + * vice versa. Respectively, these techniques are referred to as inbound and outbound. + * + * Inbound examples (creating strings from objects): + * + * pattern: api.github.com/users/:username/gists + * > [pattern stringFromObject:[GithubUser userWithUsername:@"jverkoey"]]; + * returns: api.github.com/users/jverkoey/gists + * + * pattern: api.github.com/repos/:username/:repo/issues + * > [pattern stringFromObject:[GithubRepo repoWithUsername:@"jverkoey" repo:@"sockit"]]; + * returns: api.github.com/repos/jverkoey/sockit/issues + * + * Outbound examples (performing selectors on objects with values from given strings): + * + * pattern: github.com/:username + * > [pattern performSelector:@selector(initWithUsername:) onObject:[GithubUser class] sourceString:@"github.com/jverkoey"]; + * returns: an allocated, initialized, and autoreleased GithubUser object with @"jverkoey" passed + * to the initWithUsername: method. + * + * pattern: github.com/:username/:repo + * > [pattern performSelector:@selector(initWithUsername:repoName:) onObject:[GithubUser class] sourceString:@"github.com/jverkoey/sockit"]; + * returns: an allocated, initialized, and autoreleased GithubUser object with @"jverkoey" and + * @"sockit" passed to the initWithUsername:repoName: method. + * + * pattern: github.com/:username + * > [pattern performSelector:@selector(setUsername:) onObject:githubUser sourceString:@"github.com/jverkoey"]; + * returns: nil because setUsername: does not have a return value. githubUser's username property + * is now @"jverkoey". + * + * Note 1: Parameters must be separated by string literals + * + * Pattern parameters must be separated by some sort of non-parameter character. + * This means that you can't define a pattern like :user:repo. This is because when we + * get around to wanting to decode the string back into an object we need some sort of + * delimiter between the parameters. + * + * Note 2: When colons aren't seen as parameters + * + * If you have colons in your text that aren't followed by a valid parameter name then the + * colon will be treated as static text. This is handy if you're defining a URL pattern. + * For example: @"http://github.com/:user" only has one parameter, :user. The ":" in http:// + * is treated as a string literal and not a parameter. + * + * Note 3: Escaping KVC characters + * + * If you need to use KVC characters in SOCKit patterns as literal string tokens and not + * treated with KVC then you must escape the characters using double backslashes. For example, + * @"/:userid.json" would create a pattern that uses KVC to access the json property of the + * username value. In this case, however, we wish to interpret the ".json" portion as a + * static string. + * + * In order to do so we must escape the "." using a double backslash: "\\.". For example: + * @"/:userid\\.json". This makes it possible to create strings of the form @"/3.json". + * This also works with outbound parameters, so that the string @"/3.json" can + * be used with the pattern to invoke a selector with "3" as the first argument rather + * than "3.json". + * + * You can escape the following characters: + * ":" => @"\\:" + * "@" => @"\\@" + * "." => @"\\." + * "\\" => @"\\\\" + * + * Note 4: Allocating new objects with outbound patterns + * + * SOCKit will allocate a new object of a given class if + * performSelector:onObject:sourceString: is provided a selector with "init" as a prefix + * and object is a Class. E.g. [GithubUser class]. + */ +@interface SOCPattern : NSObject { +@private + NSString* _patternString; + NSArray* _tokens; + NSArray* _parameters; +} + +/** + * Initializes a newly allocated pattern object with the given pattern string. + * + * Designated initializer. + */ +- (id)initWithString:(NSString *)string; ++ (id)patternWithString:(NSString *)string; + +/** + * Returns YES if the given string can be used with performSelector:onObject:sourceString: or + * extractParameterKeyValuesFromSourceString:. + * + * A matching string must exactly match all of the static portions of the pattern and provide + * values for each of the parameters. + * + * @param string A string that may or may not conform to this pattern. + * @returns YES if the given string conforms to this pattern, NO otherwise. + */ +- (BOOL)stringMatches:(NSString *)string; + +/** + * Performs the given selector on the object with the matching parameter values from sourceString. + * + * @param selector The selector to perform on the object. If there aren't enough + * parameters in the pattern then the excess parameters in the selector + * will be nil. + * @param object The object to perform the selector on. + * @param sourceString A string that conforms to this pattern. The parameter values from + * this string are used as the arguments when performing the selector + * on the object. + * @returns The initialized, autoreleased object if the selector is an initializer + * (prefixed with "init") and object is a Class, otherwise the return value from + * invoking the selector. + */ +- (id)performSelector:(SEL)selector onObject:(id)object sourceString:(NSString *)sourceString; + +/** + * Extracts the matching parameter values from sourceString into an NSDictionary. + * + * @param sourceString A string that conforms to this pattern. The parameter values from + * this string are extracted into the NSDictionary. + * @returns A dictionary of key value pairs. All values will be NSStrings. The keys will + * correspond to the pattern's parameter names. Duplicate key values will be + * overwritten by later values. + */ +- (NSDictionary *)parameterDictionaryFromSourceString:(NSString *)sourceString; + +/** + * Returns a string with the parameters of this pattern replaced using Key-Value Coding (KVC) + * on the receiving object. + * + * Parameters of the pattern are evaluated using valueForKeyPath:. See Apple's KVC documentation + * for more details. + * + * Key-Value Coding Fundamentals: + * http://developer.apple.com/library/ios/#documentation/cocoa/conceptual/KeyValueCoding/Articles/BasicPrinciples.html#//apple_ref/doc/uid/20002170-BAJEAIEE + * + * Collection Operators: + * http://developer.apple.com/library/ios/#documentation/cocoa/conceptual/KeyValueCoding/Articles/CollectionOperators.html#//apple_ref/doc/uid/20002176-BAJEAIEE + * + * @param object The object whose properties will be used to replace the parameters in + * the pattern. + * @returns A string with the pattern parameters replaced by the object property values. + * @see stringFromObject:withBlock: + */ +- (NSString *)stringFromObject:(id)object; + +#if NS_BLOCKS_AVAILABLE +/** + * Returns a string with the parameters of this pattern replaced using Key-Value Coding (KVC) + * on the receiving object, and the result is (optionally) modified or encoded by the block. + * + * For example, consider we have individual object values that need percent escapes added to them, + * while preserving the slashes, question marks, and ampersands of a typical resource path. + * Using blocks, this is very succinct: + * + * @code + * NSDictionary* person = [NSDictionary dictionaryWithObjectsAndKeys: + * @"SECRET|KEY",@"password", + * @"Joe Bob Briggs", @"name", nil]; + * SOCPattern* soc = [SOCPattern patternWithString:@"/people/:name/:password"]; + * NSString* actualPath = [soc stringFromObject:person withBlock:^(NSString *)propertyValue) { + * return [propertyValue stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; + * } + * NSString* expectedPath = @"/people/Joe%20Bob%20Briggs/SECRET%7CKEY"; + * @endcode + * + * @param object The object whose properties will be used to replace the parameters in + * the pattern. + * @param block An optional block (may be nil) that modifies or encodes each + * property value string. The block accepts one parameter - the property + * value as a string - and should return the modified property string. + * @returns A string with the pattern parameters replaced by the block-processed object + * property values. + * @see stringFromObject: + */ +- (NSString *)stringFromObject:(id)object withBlock:(NSString*(^)(NSString*))block; +#endif + +@end + +/** + * A convenience method for: + * + * SOCPattern* pattern = [SOCPattern patternWithString:string]; + * NSString* result = [pattern stringFromObject:object]; + * + * @see documentation for stringFromObject: + */ +NSString* SOCStringFromStringWithObject(NSString* string, id object); diff --git a/Pods/SOCKit/SOCKit.m b/Pods/SOCKit/SOCKit.m new file mode 100644 index 0000000..59e4a65 --- /dev/null +++ b/Pods/SOCKit/SOCKit.m @@ -0,0 +1,543 @@ +// +// Copyright 2011-2012 Jeff Verkoeyen +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "SOCKit.h" + +#import <objc/runtime.h> +#import <assert.h> + +typedef enum { + SOCArgumentTypeNone, + SOCArgumentTypePointer, + SOCArgumentTypeBool, + SOCArgumentTypeInteger, + SOCArgumentTypeLongLong, + SOCArgumentTypeFloat, + SOCArgumentTypeDouble, +} SOCArgumentType; + +SOCArgumentType SOCArgumentTypeForTypeAsChar(char argType); +NSString* kTemporaryBackslashToken = @"/backslash/"; + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////// +@interface SOCParameter : NSObject { +@private + NSString* _string; +} + +- (id)initWithString:(NSString *)string; ++ (id)parameterWithString:(NSString *)string; + +- (NSString *)string; + +@end + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////// +@interface SOCPattern() + +- (void)_compilePattern; + +@end + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////// +@implementation SOCPattern + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +- (void)dealloc { + [_patternString release]; _patternString = nil; + [_tokens release]; _tokens = nil; + [_parameters release]; _parameters = nil; + [super dealloc]; +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +- (id)initWithString:(NSString *)string { + if ((self = [super init])) { + _patternString = [string copy]; + + [self _compilePattern]; + } + return self; +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// ++ (id)patternWithString:(NSString *)string { + return [[[self alloc] initWithString:string] autorelease]; +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - Pattern Compilation + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +- (NSCharacterSet *)nonParameterCharacterSet { + NSMutableCharacterSet* parameterCharacterSet = [NSMutableCharacterSet alphanumericCharacterSet]; + [parameterCharacterSet addCharactersInString:@".@_"]; + NSCharacterSet* nonParameterCharacterSet = [parameterCharacterSet invertedSet]; + return nonParameterCharacterSet; +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +- (void)_compilePattern { + if ([_patternString length] == 0) { + return; + } + + NSMutableArray* tokens = [[NSMutableArray alloc] init]; + NSMutableArray* parameters = [[NSMutableArray alloc] init]; + + NSCharacterSet* nonParameterCharacterSet = [self nonParameterCharacterSet]; + + // Turn escaped backslashes into a special backslash token to avoid \\. being interpreted as + // `\` and `\.` rather than `\\` and `.`. + NSString* escapedPatternString = _patternString; + if ([escapedPatternString rangeOfString:@"\\\\"].length > 0) { + escapedPatternString = [escapedPatternString stringByReplacingOccurrencesOfString: @"\\\\" + withString: kTemporaryBackslashToken]; + } + + // Scan through the string, creating tokens that are either strings or parameters. + // Parameters are prefixed with ":". + NSScanner* scanner = [NSScanner scannerWithString:escapedPatternString]; + + // NSScanner skips whitespace and newlines by default (not ideal!). + [scanner setCharactersToBeSkipped:nil]; + + while (![scanner isAtEnd]) { + NSString* token = nil; + [scanner scanUpToString:@":" intoString:&token]; + + if ([token length] > 0) { + if (![token hasSuffix:@"\\"]) { + // Add this static text to the token list. + [tokens addObject:token]; + + } else { + // This token is escaping the next colon, so we skip the parameter creation. + [tokens addObject:[token stringByAppendingString:@":"]]; + + // Skip the colon. + [scanner setScanLocation:[scanner scanLocation] + 1]; + continue; + } + } + + if (![scanner isAtEnd]) { + // Skip the colon. + [scanner setScanLocation:[scanner scanLocation] + 1]; + + // Scanning won't modify the token if there aren't any characters to be read, so we must + // clear it before scanning again. + token = nil; + [scanner scanUpToCharactersFromSet:nonParameterCharacterSet intoString:&token]; + + if ([token length] > 0) { + // Only add parameters that have valid names. + SOCParameter* parameter = [SOCParameter parameterWithString:token]; + [parameters addObject:parameter]; + [tokens addObject:parameter]; + + } else { + // Allows for http:// to get by without creating a parameter. + [tokens addObject:@":"]; + } + } + } + + // This is an outbound pattern. + if ([parameters count] > 0) { + BOOL lastWasParameter = NO; + for (id token in tokens) { + if ([token isKindOfClass:[SOCParameter class]]) { + NSAssert(!lastWasParameter, @"Parameters must be separated by non-parameter characters."); + lastWasParameter = YES; + + } else { + lastWasParameter = NO; + } + } + } + + [_tokens release]; + _tokens = [tokens copy]; + [_parameters release]; _parameters = nil; + if ([parameters count] > 0) { + _parameters = [parameters copy]; + } + [tokens release]; tokens = nil; + [parameters release]; parameters = nil; +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +- (NSString *)_stringFromEscapedToken:(NSString *)token { + if ([token rangeOfString:@"\\"].length == 0 + && [token rangeOfString:kTemporaryBackslashToken].length == 0) { + // The common case (faster and creates fewer autoreleased strings). + return token; + + } else { + // Escaped characters may exist. + // Create a mutable copy so that we don't excessively create new autoreleased strings. + NSMutableString* mutableToken = [token mutableCopy]; + [mutableToken replaceOccurrencesOfString:@"\\." withString:@"." options:0 range:NSMakeRange(0, [mutableToken length])]; + [mutableToken replaceOccurrencesOfString:@"\\@" withString:@"@" options:0 range:NSMakeRange(0, [mutableToken length])]; + [mutableToken replaceOccurrencesOfString:@"\\:" withString:@":" options:0 range:NSMakeRange(0, [mutableToken length])]; + [mutableToken replaceOccurrencesOfString:kTemporaryBackslashToken withString:@"\\" options:0 range:NSMakeRange(0, [mutableToken length])]; + return [mutableToken autorelease]; + } +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - Public Methods + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +- (BOOL)gatherParameterValues:(NSArray**)pValues fromString:(NSString *)string { + const NSInteger stringLength = [string length]; + NSInteger validUpUntil = 0; + NSInteger matchingTokens = 0; + + NSMutableArray* values = nil; + if (nil != pValues) { + values = [NSMutableArray array]; + } + + NSInteger tokenIndex = 0; + for (id token in _tokens) { + + if ([token isKindOfClass:[NSString class]]) { + // Replace the escaped characters in the token before we start comparing the string. + token = [self _stringFromEscapedToken:token]; + + NSInteger tokenLength = [token length]; + if (validUpUntil + tokenLength > stringLength) { + // There aren't enough characters in the string to satisfy this token. + break; + } + if (![[string substringWithRange:NSMakeRange(validUpUntil, tokenLength)] + isEqualToString:token]) { + // The tokens don't match up. + break; + } + + // The string token matches. + validUpUntil += tokenLength; + ++matchingTokens; + + } else { + NSInteger parameterLocation = validUpUntil; + + // Look ahead for the next string token match. + if (tokenIndex + 1 < [_tokens count]) { + NSString* nextToken = [self _stringFromEscapedToken:[_tokens objectAtIndex:tokenIndex + 1]]; + NSAssert([nextToken isKindOfClass:[NSString class]], @"The token following a parameter must be a string."); + + NSRange nextTokenRange = [string rangeOfString:nextToken options:0 range:NSMakeRange(validUpUntil, stringLength - validUpUntil)]; + if (nextTokenRange.length == 0) { + // Couldn't find the next token. + break; + } + if (nextTokenRange.location == validUpUntil) { + // This parameter is empty. + break; + } + + validUpUntil = nextTokenRange.location; + ++matchingTokens; + + } else { + // Anything goes until the end of the string then. + if (validUpUntil == stringLength) { + // The last parameter is empty. + break; + } + + validUpUntil = stringLength; + ++matchingTokens; + } + + NSRange parameterRange = NSMakeRange(parameterLocation, validUpUntil - parameterLocation); + [values addObject:[string substringWithRange:parameterRange]]; + } + + ++tokenIndex; + } + + if (nil != pValues) { + *pValues = [[values copy] autorelease]; + } + + return validUpUntil == stringLength && matchingTokens == [_tokens count]; +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +- (BOOL)stringMatches:(NSString *)string { + return [self gatherParameterValues:nil fromString:string]; +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +- (void)setArgument:(NSString*)text withType:(SOCArgumentType)type atIndex:(NSInteger)index forInvocation:(NSInvocation*)invocation { + // There are two implicit arguments with an invocation. + index+=2; + + switch (type) { + case SOCArgumentTypeNone: { + break; + } + case SOCArgumentTypeInteger: { + int val = [text intValue]; + [invocation setArgument:&val atIndex:index]; + break; + } + case SOCArgumentTypeLongLong: { + long long val = [text longLongValue]; + [invocation setArgument:&val atIndex:index]; + break; + } + case SOCArgumentTypeFloat: { + float val = [text floatValue]; + [invocation setArgument:&val atIndex:index]; + break; + } + case SOCArgumentTypeDouble: { + double val = [text doubleValue]; + [invocation setArgument:&val atIndex:index]; + break; + } + case SOCArgumentTypeBool: { + BOOL val = [text boolValue]; + [invocation setArgument:&val atIndex:index]; + break; + } + default: { + [invocation setArgument:&text atIndex:index]; + break; + } + } +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +- (void)setArgumentsFromValues:(NSArray *)values forInvocation:(NSInvocation *)invocation { + Method method = class_getInstanceMethod([invocation.target class], invocation.selector); + NSAssert(nil != method, @"The method must exist with the given invocation target."); + + for (NSInteger ix = 0; ix < [values count]; ++ix) { + NSString* value = [values objectAtIndex:ix]; + + char argType[4]; + method_getArgumentType(method, (unsigned int) ix + 2, argType, sizeof(argType) / sizeof(argType[0])); + SOCArgumentType type = SOCArgumentTypeForTypeAsChar(argType[0]); + + [self setArgument:value withType:type atIndex:ix forInvocation:invocation]; + } +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +- (id)performSelector:(SEL)selector onObject:(id)object sourceString:(NSString *)sourceString { + BOOL isInitializer = [NSStringFromSelector(selector) hasPrefix:@"init"] && [object class] == object; + + if (isInitializer) { + object = [[object alloc] autorelease]; + } + + NSArray* values = nil; + BOOL succeeded = [self gatherParameterValues:&values fromString:sourceString]; + NSAssert(succeeded, @"The pattern can't be used with this string."); + + id returnValue = nil; + + if (succeeded) { + NSMethodSignature* sig = [object methodSignatureForSelector:selector]; + NSAssert(nil != sig, @"%@ does not respond to selector: '%@'", object, NSStringFromSelector(selector)); + NSInvocation* invocation = [NSInvocation invocationWithMethodSignature:sig]; + [invocation setTarget:object]; + [invocation setSelector:selector]; + [self setArgumentsFromValues:values forInvocation:invocation]; + [invocation invoke]; + + if (sig.methodReturnLength) { + [invocation getReturnValue:&returnValue]; + } + } + + return returnValue; +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +- (NSDictionary *)parameterDictionaryFromSourceString:(NSString *)sourceString { + NSMutableDictionary* kvs = [[NSMutableDictionary alloc] initWithCapacity:[_parameters count]]; + + NSArray* values = nil; + BOOL succeeded = [self gatherParameterValues:&values fromString:sourceString]; + NSAssert(succeeded, @"The pattern can't be used with this string."); + + NSDictionary* result = nil; + + if (succeeded) { + for (NSInteger ix = 0; ix < [values count]; ++ix) { + SOCParameter* parameter = [_parameters objectAtIndex:ix]; + id value = [values objectAtIndex:ix]; + [kvs setObject:value forKey:parameter.string]; + } + + result = [[kvs copy] autorelease]; + [kvs release]; kvs = nil; + } + + return result; +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +- (NSString *)_stringWithParameterValues:(NSDictionary *)parameterValues { + NSMutableString* accumulator = [[NSMutableString alloc] initWithCapacity:[_patternString length]]; + + for (id token in _tokens) { + if ([token isKindOfClass:[NSString class]]) { + [accumulator appendString:[self _stringFromEscapedToken:token]]; + + } else { + SOCParameter* parameter = token; + [accumulator appendString:[parameterValues objectForKey:parameter.string]]; + } + } + + NSString* result = nil; + result = [[accumulator copy] autorelease]; + [accumulator release]; accumulator = nil; + return result; +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +- (NSString *)stringFromObject:(id)object { + if ([_tokens count] == 0) { + return @""; + } + NSMutableDictionary* parameterValues = + [NSMutableDictionary dictionaryWithCapacity:[_parameters count]]; + for (SOCParameter* parameter in _parameters) { + NSString* stringValue = [NSString stringWithFormat:@"%@", [object valueForKeyPath:parameter.string]]; + [parameterValues setObject:stringValue forKey:parameter.string]; + } + return [self _stringWithParameterValues:parameterValues]; +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +#if NS_BLOCKS_AVAILABLE +- (NSString *)stringFromObject:(id)object withBlock:(NSString *(^)(NSString*))block { + if ([_tokens count] == 0) { + return @""; + } + NSMutableDictionary* parameterValues = [NSMutableDictionary dictionaryWithCapacity:[_parameters count]]; + for (SOCParameter* parameter in _parameters) { + NSString* stringValue = [NSString stringWithFormat:@"%@", [object valueForKeyPath:parameter.string]]; + if (nil != block) { + stringValue = block(stringValue); + } + if (nil != stringValue) { + [parameterValues setObject:stringValue forKey:parameter.string]; + } + } + return [self _stringWithParameterValues:parameterValues]; +} +#endif + +@end + +/////////////////////////////////////////////////////////////////////////////////////////////////// +@implementation SOCParameter + +- (void)dealloc { + [_string release]; _string = nil; + [super dealloc]; +} + +- (id)initWithString:(NSString *)string { + if ((self = [super init])) { + _string = [string copy]; + } + return self; +} + ++ (id)parameterWithString:(NSString *)string { + return [[[self alloc] initWithString:string] autorelease]; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"Parameter: %@", _string]; +} + +- (NSString *)string { + return [[_string retain] autorelease]; +} + +@end + +/////////////////////////////////////////////////////////////////////////////////////////////////// +SOCArgumentType SOCArgumentTypeForTypeAsChar(char argType) { + if (argType == 'c' || argType == 'i' || argType == 's' || argType == 'l' || argType == 'C' + || argType == 'I' || argType == 'S' || argType == 'L') { + return SOCArgumentTypeInteger; + + } else if (argType == 'q' || argType == 'Q') { + return SOCArgumentTypeLongLong; + + } else if (argType == 'f') { + return SOCArgumentTypeFloat; + + } else if (argType == 'd') { + return SOCArgumentTypeDouble; + + } else if (argType == 'B') { + return SOCArgumentTypeBool; + + } else { + return SOCArgumentTypePointer; + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +NSString* SOCStringFromStringWithObject(NSString* string, id object) { + SOCPattern* pattern = [[SOCPattern alloc] initWithString:string]; + NSString* result = [pattern stringFromObject:object]; + [pattern release]; + return result; +} diff --git a/Pods/Target Support Files/AFNetworking/AFNetworking-Private.xcconfig b/Pods/Target Support Files/AFNetworking/AFNetworking-Private.xcconfig new file mode 100644 index 0000000..63afb4f --- /dev/null +++ b/Pods/Target Support Files/AFNetworking/AFNetworking-Private.xcconfig @@ -0,0 +1,6 @@ +#include "AFNetworking.xcconfig" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/AFNetworking" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/AFNetworking" "${PODS_ROOT}/Headers/Public/GoogleMaps" "${PODS_ROOT}/Headers/Public/GoogleMaps/GoogleMaps" "${PODS_ROOT}/Headers/Public/ISO8601DateFormatterValueTransformer" "${PODS_ROOT}/Headers/Public/RKValueTransformers" "${PODS_ROOT}/Headers/Public/RestKit" "${PODS_ROOT}/Headers/Public/RestKit/CoreData" "${PODS_ROOT}/Headers/Public/RestKit/Network" "${PODS_ROOT}/Headers/Public/RestKit/ObjectMapping" "${PODS_ROOT}/Headers/Public/RestKit/Support" "${PODS_ROOT}/Headers/Public/SOCKit" "${PODS_ROOT}/Headers/Public/TransitionKit" "${PODS_ROOT}/Headers/Public/Vendor/LibComponentLogging/Core" +OTHER_LDFLAGS = ${AFNETWORKING_OTHER_LDFLAGS} +PODS_ROOT = ${SRCROOT} +SKIP_INSTALL = YES \ No newline at end of file diff --git a/Pods/Target Support Files/AFNetworking/AFNetworking-dummy.m b/Pods/Target Support Files/AFNetworking/AFNetworking-dummy.m new file mode 100644 index 0000000..6a29cf8 --- /dev/null +++ b/Pods/Target Support Files/AFNetworking/AFNetworking-dummy.m @@ -0,0 +1,5 @@ +#import <Foundation/Foundation.h> +@interface PodsDummy_AFNetworking : NSObject +@end +@implementation PodsDummy_AFNetworking +@end diff --git a/Pods/Target Support Files/AFNetworking/AFNetworking-prefix.pch b/Pods/Target Support Files/AFNetworking/AFNetworking-prefix.pch new file mode 100644 index 0000000..8fb0298 --- /dev/null +++ b/Pods/Target Support Files/AFNetworking/AFNetworking-prefix.pch @@ -0,0 +1,15 @@ +#ifdef __OBJC__ +#import <UIKit/UIKit.h> +#endif + +#import <Availability.h> + +#if __IPHONE_OS_VERSION_MIN_REQUIRED + #import <SystemConfiguration/SystemConfiguration.h> + #import <MobileCoreServices/MobileCoreServices.h> + #import <Security/Security.h> +#else + #import <SystemConfiguration/SystemConfiguration.h> + #import <CoreServices/CoreServices.h> + #import <Security/Security.h> +#endif diff --git a/Pods/Target Support Files/AFNetworking/AFNetworking.xcconfig b/Pods/Target Support Files/AFNetworking/AFNetworking.xcconfig new file mode 100644 index 0000000..b0b2d52 --- /dev/null +++ b/Pods/Target Support Files/AFNetworking/AFNetworking.xcconfig @@ -0,0 +1 @@ +AFNETWORKING_OTHER_LDFLAGS = -framework "CoreGraphics" -framework "MobileCoreServices" -framework "Security" -framework "SystemConfiguration" \ No newline at end of file diff --git a/Pods/Target Support Files/ISO8601DateFormatterValueTransformer/ISO8601DateFormatterValueTransformer-Private.xcconfig b/Pods/Target Support Files/ISO8601DateFormatterValueTransformer/ISO8601DateFormatterValueTransformer-Private.xcconfig new file mode 100644 index 0000000..92e46e7 --- /dev/null +++ b/Pods/Target Support Files/ISO8601DateFormatterValueTransformer/ISO8601DateFormatterValueTransformer-Private.xcconfig @@ -0,0 +1,5 @@ +#include "ISO8601DateFormatterValueTransformer.xcconfig" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/ISO8601DateFormatterValueTransformer" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/AFNetworking" "${PODS_ROOT}/Headers/Public/GoogleMaps" "${PODS_ROOT}/Headers/Public/GoogleMaps/GoogleMaps" "${PODS_ROOT}/Headers/Public/ISO8601DateFormatterValueTransformer" "${PODS_ROOT}/Headers/Public/RKValueTransformers" "${PODS_ROOT}/Headers/Public/RestKit" "${PODS_ROOT}/Headers/Public/RestKit/CoreData" "${PODS_ROOT}/Headers/Public/RestKit/Network" "${PODS_ROOT}/Headers/Public/RestKit/ObjectMapping" "${PODS_ROOT}/Headers/Public/RestKit/Support" "${PODS_ROOT}/Headers/Public/SOCKit" "${PODS_ROOT}/Headers/Public/TransitionKit" "${PODS_ROOT}/Headers/Public/Vendor/LibComponentLogging/Core" +PODS_ROOT = ${SRCROOT} +SKIP_INSTALL = YES \ No newline at end of file diff --git a/Pods/Target Support Files/ISO8601DateFormatterValueTransformer/ISO8601DateFormatterValueTransformer-dummy.m b/Pods/Target Support Files/ISO8601DateFormatterValueTransformer/ISO8601DateFormatterValueTransformer-dummy.m new file mode 100644 index 0000000..8a45508 --- /dev/null +++ b/Pods/Target Support Files/ISO8601DateFormatterValueTransformer/ISO8601DateFormatterValueTransformer-dummy.m @@ -0,0 +1,5 @@ +#import <Foundation/Foundation.h> +@interface PodsDummy_ISO8601DateFormatterValueTransformer : NSObject +@end +@implementation PodsDummy_ISO8601DateFormatterValueTransformer +@end diff --git a/Pods/Target Support Files/ISO8601DateFormatterValueTransformer/ISO8601DateFormatterValueTransformer-prefix.pch b/Pods/Target Support Files/ISO8601DateFormatterValueTransformer/ISO8601DateFormatterValueTransformer-prefix.pch new file mode 100644 index 0000000..aa992a4 --- /dev/null +++ b/Pods/Target Support Files/ISO8601DateFormatterValueTransformer/ISO8601DateFormatterValueTransformer-prefix.pch @@ -0,0 +1,4 @@ +#ifdef __OBJC__ +#import <UIKit/UIKit.h> +#endif + diff --git a/Pods/Target Support Files/ISO8601DateFormatterValueTransformer/ISO8601DateFormatterValueTransformer.xcconfig b/Pods/Target Support Files/ISO8601DateFormatterValueTransformer/ISO8601DateFormatterValueTransformer.xcconfig new file mode 100644 index 0000000..e69de29 diff --git a/Pods/Target Support Files/Pods/Pods-acknowledgements.markdown b/Pods/Target Support Files/Pods/Pods-acknowledgements.markdown new file mode 100644 index 0000000..768a13d --- /dev/null +++ b/Pods/Target Support Files/Pods/Pods-acknowledgements.markdown @@ -0,0 +1,1045 @@ +# Acknowledgements +This application makes use of the following third party libraries: + +## AFNetworking + +Copyright (c) 2013-2014 AFNetworking (http://afnetworking.com/) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +## GoogleMaps + +If you use the Google Maps SDK for iOS in your application, you must +include the attribution text as part of a legal notices section in your +application. Including legal notices as an independent menu item, or as +part of an "About" menu item, is recommended. + +You can get the attribution text by making a call to +[GMSServices openSourceLicenseInfo]. + + +## ISO8601DateFormatterValueTransformer + +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright +owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, "control" means (i) the power, direct or +indirect, to cause the direction or management of such entity, whether by +contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising +permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including +but not limited to software source code, documentation source, and configuration +files. + +"Object" form shall mean any form resulting from mechanical transformation or +translation of a Source form, including but not limited to compiled object code, +generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made +available under the License, as indicated by a copyright notice that is included +in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that +is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative Works +shall not include works that remain separable from, or merely link (or bind by +name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version +of the Work and any modifications or additions to that Work or Derivative Works +thereof, that is intentionally submitted to Licensor for inclusion in the Work +by the copyright owner or by an individual or Legal Entity authorized to submit +on behalf of the copyright owner. For the purposes of this definition, +"submitted" means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and +issue tracking systems that are managed by, or on behalf of, the Licensor for +the purpose of discussing and improving the Work, but excluding communication +that is conspicuously marked or otherwise designated in writing by the copyright +owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the Work and such +Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where +such license applies only to those patent claims licensable by such Contributor +that are necessarily infringed by their Contribution(s) alone or by combination +of their Contribution(s) with the Work to which such Contribution(s) was +submitted. If You institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work or a +Contribution incorporated within the Work constitutes direct or contributory +patent infringement, then any patent licenses granted to You under this License +for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof +in any medium, with or without modifications, and in Source or Object form, +provided that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of +this License; and +You must cause any modified files to carry prominent notices stating that You +changed the files; and +You must retain, in the Source form of any Derivative Works that You distribute, +all copyright, patent, trademark, and attribution notices from the Source form +of the Work, excluding those notices that do not pertain to any part of the +Derivative Works; and +If the Work includes a "NOTICE" text file as part of its distribution, then any +Derivative Works that You distribute must include a readable copy of the +attribution notices contained within such NOTICE file, excluding those notices +that do not pertain to any part of the Derivative Works, in at least one of the +following places: within a NOTICE text file distributed as part of the +Derivative Works; within the Source form or documentation, if provided along +with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents of +the NOTICE file are for informational purposes only and do not modify the +License. You may add Your own attribution notices within Derivative Works that +You distribute, alongside or as an addendum to the NOTICE text from the Work, +provided that such additional attribution notices cannot be construed as +modifying the License. +You may add Your own copyright statement to Your modifications and may provide +additional or different license terms and conditions for use, reproduction, or +distribution of Your modifications, or for any such Derivative Works as a whole, +provided Your use, reproduction, and distribution of the Work otherwise complies +with the conditions stated in this License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted +for inclusion in the Work by You to the Licensor shall be under the terms and +conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of +any separate license agreement you may have executed with Licensor regarding +such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides the +Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, +including, without limitation, any warranties or conditions of TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are +solely responsible for determining the appropriateness of using or +redistributing the Work and assume any risks associated with Your exercise of +permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), +contract, or otherwise, unless required by applicable law (such as deliberate +and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, incidental, +or consequential damages of any character arising as a result of this License or +out of the use or inability to use the Work (including but not limited to +damages for loss of goodwill, work stoppage, computer failure or malfunction, or +any and all other commercial damages or losses), even if such Contributor has +been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to +offer, and charge a fee for, acceptance of support, warranty, indemnity, or +other liability obligations and/or rights consistent with this License. However, +in accepting such obligations, You may act only on Your own behalf and on Your +sole responsibility, not on behalf of any other Contributor, and only if You +agree to indemnify, defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason of your +accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work + +To apply the Apache License to your work, attach the following boilerplate +notice, with the fields enclosed by brackets "[]" replaced with your own +identifying information. (Don't include the brackets!) The text should be +enclosed in the appropriate comment syntax for the file format. We also +recommend that a file or class name and description of purpose be included on +the same "printed page" as the copyright notice for easier identification within +third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +## RKValueTransformers + +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright +owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, "control" means (i) the power, direct or +indirect, to cause the direction or management of such entity, whether by +contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising +permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including +but not limited to software source code, documentation source, and configuration +files. + +"Object" form shall mean any form resulting from mechanical transformation or +translation of a Source form, including but not limited to compiled object code, +generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made +available under the License, as indicated by a copyright notice that is included +in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that +is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative Works +shall not include works that remain separable from, or merely link (or bind by +name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version +of the Work and any modifications or additions to that Work or Derivative Works +thereof, that is intentionally submitted to Licensor for inclusion in the Work +by the copyright owner or by an individual or Legal Entity authorized to submit +on behalf of the copyright owner. For the purposes of this definition, +"submitted" means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and +issue tracking systems that are managed by, or on behalf of, the Licensor for +the purpose of discussing and improving the Work, but excluding communication +that is conspicuously marked or otherwise designated in writing by the copyright +owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the Work and such +Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where +such license applies only to those patent claims licensable by such Contributor +that are necessarily infringed by their Contribution(s) alone or by combination +of their Contribution(s) with the Work to which such Contribution(s) was +submitted. If You institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work or a +Contribution incorporated within the Work constitutes direct or contributory +patent infringement, then any patent licenses granted to You under this License +for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof +in any medium, with or without modifications, and in Source or Object form, +provided that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of +this License; and +You must cause any modified files to carry prominent notices stating that You +changed the files; and +You must retain, in the Source form of any Derivative Works that You distribute, +all copyright, patent, trademark, and attribution notices from the Source form +of the Work, excluding those notices that do not pertain to any part of the +Derivative Works; and +If the Work includes a "NOTICE" text file as part of its distribution, then any +Derivative Works that You distribute must include a readable copy of the +attribution notices contained within such NOTICE file, excluding those notices +that do not pertain to any part of the Derivative Works, in at least one of the +following places: within a NOTICE text file distributed as part of the +Derivative Works; within the Source form or documentation, if provided along +with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents of +the NOTICE file are for informational purposes only and do not modify the +License. You may add Your own attribution notices within Derivative Works that +You distribute, alongside or as an addendum to the NOTICE text from the Work, +provided that such additional attribution notices cannot be construed as +modifying the License. +You may add Your own copyright statement to Your modifications and may provide +additional or different license terms and conditions for use, reproduction, or +distribution of Your modifications, or for any such Derivative Works as a whole, +provided Your use, reproduction, and distribution of the Work otherwise complies +with the conditions stated in this License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted +for inclusion in the Work by You to the Licensor shall be under the terms and +conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of +any separate license agreement you may have executed with Licensor regarding +such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides the +Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, +including, without limitation, any warranties or conditions of TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are +solely responsible for determining the appropriateness of using or +redistributing the Work and assume any risks associated with Your exercise of +permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), +contract, or otherwise, unless required by applicable law (such as deliberate +and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, incidental, +or consequential damages of any character arising as a result of this License or +out of the use or inability to use the Work (including but not limited to +damages for loss of goodwill, work stoppage, computer failure or malfunction, or +any and all other commercial damages or losses), even if such Contributor has +been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to +offer, and charge a fee for, acceptance of support, warranty, indemnity, or +other liability obligations and/or rights consistent with this License. However, +in accepting such obligations, You may act only on Your own behalf and on Your +sole responsibility, not on behalf of any other Contributor, and only if You +agree to indemnify, defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason of your +accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work + +To apply the Apache License to your work, attach the following boilerplate +notice, with the fields enclosed by brackets "[]" replaced with your own +identifying information. (Don't include the brackets!) The text should be +enclosed in the appropriate comment syntax for the file format. We also +recommend that a file or class name and description of purpose be included on +the same "printed page" as the copyright notice for easier identification within +third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +## RestKit + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2009-2012 The RestKit Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +## SOCKit + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +## TransitionKit + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2009-2012 The RestKit Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +Generated by CocoaPods - http://cocoapods.org diff --git a/Pods/Target Support Files/Pods/Pods-acknowledgements.plist b/Pods/Target Support Files/Pods/Pods-acknowledgements.plist new file mode 100644 index 0000000..94ba4c2 --- /dev/null +++ b/Pods/Target Support Files/Pods/Pods-acknowledgements.plist @@ -0,0 +1,1099 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>PreferenceSpecifiers</key> + <array> + <dict> + <key>FooterText</key> + <string>This application makes use of the following third party libraries:</string> + <key>Title</key> + <string>Acknowledgements</string> + <key>Type</key> + <string>PSGroupSpecifier</string> + </dict> + <dict> + <key>FooterText</key> + <string>Copyright (c) 2013-2014 AFNetworking (http://afnetworking.com/) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +</string> + <key>Title</key> + <string>AFNetworking</string> + <key>Type</key> + <string>PSGroupSpecifier</string> + </dict> + <dict> + <key>FooterText</key> + <string>If you use the Google Maps SDK for iOS in your application, you must +include the attribution text as part of a legal notices section in your +application. Including legal notices as an independent menu item, or as +part of an "About" menu item, is recommended. + +You can get the attribution text by making a call to +[GMSServices openSourceLicenseInfo]. +</string> + <key>Title</key> + <string>GoogleMaps</string> + <key>Type</key> + <string>PSGroupSpecifier</string> + </dict> + <dict> + <key>FooterText</key> + <string>Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright +owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, "control" means (i) the power, direct or +indirect, to cause the direction or management of such entity, whether by +contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising +permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including +but not limited to software source code, documentation source, and configuration +files. + +"Object" form shall mean any form resulting from mechanical transformation or +translation of a Source form, including but not limited to compiled object code, +generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made +available under the License, as indicated by a copyright notice that is included +in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that +is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative Works +shall not include works that remain separable from, or merely link (or bind by +name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version +of the Work and any modifications or additions to that Work or Derivative Works +thereof, that is intentionally submitted to Licensor for inclusion in the Work +by the copyright owner or by an individual or Legal Entity authorized to submit +on behalf of the copyright owner. For the purposes of this definition, +"submitted" means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and +issue tracking systems that are managed by, or on behalf of, the Licensor for +the purpose of discussing and improving the Work, but excluding communication +that is conspicuously marked or otherwise designated in writing by the copyright +owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the Work and such +Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where +such license applies only to those patent claims licensable by such Contributor +that are necessarily infringed by their Contribution(s) alone or by combination +of their Contribution(s) with the Work to which such Contribution(s) was +submitted. If You institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work or a +Contribution incorporated within the Work constitutes direct or contributory +patent infringement, then any patent licenses granted to You under this License +for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof +in any medium, with or without modifications, and in Source or Object form, +provided that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of +this License; and +You must cause any modified files to carry prominent notices stating that You +changed the files; and +You must retain, in the Source form of any Derivative Works that You distribute, +all copyright, patent, trademark, and attribution notices from the Source form +of the Work, excluding those notices that do not pertain to any part of the +Derivative Works; and +If the Work includes a "NOTICE" text file as part of its distribution, then any +Derivative Works that You distribute must include a readable copy of the +attribution notices contained within such NOTICE file, excluding those notices +that do not pertain to any part of the Derivative Works, in at least one of the +following places: within a NOTICE text file distributed as part of the +Derivative Works; within the Source form or documentation, if provided along +with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents of +the NOTICE file are for informational purposes only and do not modify the +License. You may add Your own attribution notices within Derivative Works that +You distribute, alongside or as an addendum to the NOTICE text from the Work, +provided that such additional attribution notices cannot be construed as +modifying the License. +You may add Your own copyright statement to Your modifications and may provide +additional or different license terms and conditions for use, reproduction, or +distribution of Your modifications, or for any such Derivative Works as a whole, +provided Your use, reproduction, and distribution of the Work otherwise complies +with the conditions stated in this License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted +for inclusion in the Work by You to the Licensor shall be under the terms and +conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of +any separate license agreement you may have executed with Licensor regarding +such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides the +Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, +including, without limitation, any warranties or conditions of TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are +solely responsible for determining the appropriateness of using or +redistributing the Work and assume any risks associated with Your exercise of +permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), +contract, or otherwise, unless required by applicable law (such as deliberate +and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, incidental, +or consequential damages of any character arising as a result of this License or +out of the use or inability to use the Work (including but not limited to +damages for loss of goodwill, work stoppage, computer failure or malfunction, or +any and all other commercial damages or losses), even if such Contributor has +been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to +offer, and charge a fee for, acceptance of support, warranty, indemnity, or +other liability obligations and/or rights consistent with this License. However, +in accepting such obligations, You may act only on Your own behalf and on Your +sole responsibility, not on behalf of any other Contributor, and only if You +agree to indemnify, defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason of your +accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work + +To apply the Apache License to your work, attach the following boilerplate +notice, with the fields enclosed by brackets "[]" replaced with your own +identifying information. (Don't include the brackets!) The text should be +enclosed in the appropriate comment syntax for the file format. We also +recommend that a file or class name and description of purpose be included on +the same "printed page" as the copyright notice for easier identification within +third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +</string> + <key>Title</key> + <string>ISO8601DateFormatterValueTransformer</string> + <key>Type</key> + <string>PSGroupSpecifier</string> + </dict> + <dict> + <key>FooterText</key> + <string>Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright +owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, "control" means (i) the power, direct or +indirect, to cause the direction or management of such entity, whether by +contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising +permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including +but not limited to software source code, documentation source, and configuration +files. + +"Object" form shall mean any form resulting from mechanical transformation or +translation of a Source form, including but not limited to compiled object code, +generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made +available under the License, as indicated by a copyright notice that is included +in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that +is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative Works +shall not include works that remain separable from, or merely link (or bind by +name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version +of the Work and any modifications or additions to that Work or Derivative Works +thereof, that is intentionally submitted to Licensor for inclusion in the Work +by the copyright owner or by an individual or Legal Entity authorized to submit +on behalf of the copyright owner. For the purposes of this definition, +"submitted" means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and +issue tracking systems that are managed by, or on behalf of, the Licensor for +the purpose of discussing and improving the Work, but excluding communication +that is conspicuously marked or otherwise designated in writing by the copyright +owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the Work and such +Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where +such license applies only to those patent claims licensable by such Contributor +that are necessarily infringed by their Contribution(s) alone or by combination +of their Contribution(s) with the Work to which such Contribution(s) was +submitted. If You institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work or a +Contribution incorporated within the Work constitutes direct or contributory +patent infringement, then any patent licenses granted to You under this License +for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof +in any medium, with or without modifications, and in Source or Object form, +provided that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of +this License; and +You must cause any modified files to carry prominent notices stating that You +changed the files; and +You must retain, in the Source form of any Derivative Works that You distribute, +all copyright, patent, trademark, and attribution notices from the Source form +of the Work, excluding those notices that do not pertain to any part of the +Derivative Works; and +If the Work includes a "NOTICE" text file as part of its distribution, then any +Derivative Works that You distribute must include a readable copy of the +attribution notices contained within such NOTICE file, excluding those notices +that do not pertain to any part of the Derivative Works, in at least one of the +following places: within a NOTICE text file distributed as part of the +Derivative Works; within the Source form or documentation, if provided along +with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents of +the NOTICE file are for informational purposes only and do not modify the +License. You may add Your own attribution notices within Derivative Works that +You distribute, alongside or as an addendum to the NOTICE text from the Work, +provided that such additional attribution notices cannot be construed as +modifying the License. +You may add Your own copyright statement to Your modifications and may provide +additional or different license terms and conditions for use, reproduction, or +distribution of Your modifications, or for any such Derivative Works as a whole, +provided Your use, reproduction, and distribution of the Work otherwise complies +with the conditions stated in this License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted +for inclusion in the Work by You to the Licensor shall be under the terms and +conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of +any separate license agreement you may have executed with Licensor regarding +such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides the +Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, +including, without limitation, any warranties or conditions of TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are +solely responsible for determining the appropriateness of using or +redistributing the Work and assume any risks associated with Your exercise of +permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), +contract, or otherwise, unless required by applicable law (such as deliberate +and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, incidental, +or consequential damages of any character arising as a result of this License or +out of the use or inability to use the Work (including but not limited to +damages for loss of goodwill, work stoppage, computer failure or malfunction, or +any and all other commercial damages or losses), even if such Contributor has +been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to +offer, and charge a fee for, acceptance of support, warranty, indemnity, or +other liability obligations and/or rights consistent with this License. However, +in accepting such obligations, You may act only on Your own behalf and on Your +sole responsibility, not on behalf of any other Contributor, and only if You +agree to indemnify, defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason of your +accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work + +To apply the Apache License to your work, attach the following boilerplate +notice, with the fields enclosed by brackets "[]" replaced with your own +identifying information. (Don't include the brackets!) The text should be +enclosed in the appropriate comment syntax for the file format. We also +recommend that a file or class name and description of purpose be included on +the same "printed page" as the copyright notice for easier identification within +third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +</string> + <key>Title</key> + <string>RKValueTransformers</string> + <key>Type</key> + <string>PSGroupSpecifier</string> + </dict> + <dict> + <key>FooterText</key> + <string> + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2009-2012 The RestKit Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +</string> + <key>Title</key> + <string>RestKit</string> + <key>Type</key> + <string>PSGroupSpecifier</string> + </dict> + <dict> + <key>FooterText</key> + <string> + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +</string> + <key>Title</key> + <string>SOCKit</string> + <key>Type</key> + <string>PSGroupSpecifier</string> + </dict> + <dict> + <key>FooterText</key> + <string> + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2009-2012 The RestKit Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +</string> + <key>Title</key> + <string>TransitionKit</string> + <key>Type</key> + <string>PSGroupSpecifier</string> + </dict> + <dict> + <key>FooterText</key> + <string>Generated by CocoaPods - http://cocoapods.org</string> + <key>Title</key> + <string></string> + <key>Type</key> + <string>PSGroupSpecifier</string> + </dict> + </array> + <key>StringsTable</key> + <string>Acknowledgements</string> + <key>Title</key> + <string>Acknowledgements</string> +</dict> +</plist> diff --git a/Pods/Target Support Files/Pods/Pods-dummy.m b/Pods/Target Support Files/Pods/Pods-dummy.m new file mode 100644 index 0000000..ade64bd --- /dev/null +++ b/Pods/Target Support Files/Pods/Pods-dummy.m @@ -0,0 +1,5 @@ +#import <Foundation/Foundation.h> +@interface PodsDummy_Pods : NSObject +@end +@implementation PodsDummy_Pods +@end diff --git a/Pods/Target Support Files/Pods/Pods-resources.sh b/Pods/Target Support Files/Pods/Pods-resources.sh new file mode 100755 index 0000000..14dec4d --- /dev/null +++ b/Pods/Target Support Files/Pods/Pods-resources.sh @@ -0,0 +1,101 @@ +#!/bin/sh +set -e + +mkdir -p "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" + +RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt +> "$RESOURCES_TO_COPY" + +XCASSET_FILES=() + +realpath() { + DIRECTORY="$(cd "${1%/*}" && pwd)" + FILENAME="${1##*/}" + echo "$DIRECTORY/$FILENAME" +} + +install_resource() +{ + case $1 in + *.storyboard) + echo "ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile ${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .storyboard`.storyboardc ${PODS_ROOT}/$1 --sdk ${SDKROOT}" + ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .storyboard`.storyboardc" "${PODS_ROOT}/$1" --sdk "${SDKROOT}" + ;; + *.xib) + echo "ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile ${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .xib`.nib ${PODS_ROOT}/$1 --sdk ${SDKROOT}" + ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .xib`.nib" "${PODS_ROOT}/$1" --sdk "${SDKROOT}" + ;; + *.framework) + echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" + mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" + echo "rsync -av ${PODS_ROOT}/$1 ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" + rsync -av "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" + ;; + *.xcdatamodel) + echo "xcrun momc \"${PODS_ROOT}/$1\" \"${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1"`.mom\"" + xcrun momc "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcdatamodel`.mom" + ;; + *.xcdatamodeld) + echo "xcrun momc \"${PODS_ROOT}/$1\" \"${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcdatamodeld`.momd\"" + xcrun momc "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcdatamodeld`.momd" + ;; + *.xcmappingmodel) + echo "xcrun mapc \"${PODS_ROOT}/$1\" \"${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcmappingmodel`.cdm\"" + xcrun mapc "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcmappingmodel`.cdm" + ;; + *.xcassets) + ABSOLUTE_XCASSET_FILE=$(realpath "${PODS_ROOT}/$1") + XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE") + ;; + /*) + echo "$1" + echo "$1" >> "$RESOURCES_TO_COPY" + ;; + *) + echo "${PODS_ROOT}/$1" + echo "${PODS_ROOT}/$1" >> "$RESOURCES_TO_COPY" + ;; + esac +} +if [[ "$CONFIGURATION" == "Debug" ]]; then + install_resource "GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle" +fi +if [[ "$CONFIGURATION" == "Release" ]]; then + install_resource "GoogleMaps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle" +fi + +mkdir -p "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" +rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" +if [[ "${ACTION}" == "install" ]]; then + mkdir -p "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" + rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" +fi +rm -f "$RESOURCES_TO_COPY" + +if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "$XCASSET_FILES" ] +then + case "${TARGETED_DEVICE_FAMILY}" in + 1,2) + TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone" + ;; + 1) + TARGET_DEVICE_ARGS="--target-device iphone" + ;; + 2) + TARGET_DEVICE_ARGS="--target-device ipad" + ;; + *) + TARGET_DEVICE_ARGS="--target-device mac" + ;; + esac + + # Find all other xcassets (this unfortunately includes those of path pods and other targets). + OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d) + while read line; do + if [[ $line != "`realpath $PODS_ROOT`*" ]]; then + XCASSET_FILES+=("$line") + fi + done <<<"$OTHER_XCASSETS" + + printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${IPHONEOS_DEPLOYMENT_TARGET}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" +fi diff --git a/Pods/Target Support Files/Pods/Pods.debug.xcconfig b/Pods/Target Support Files/Pods/Pods.debug.xcconfig new file mode 100644 index 0000000..f621237 --- /dev/null +++ b/Pods/Target Support Files/Pods/Pods.debug.xcconfig @@ -0,0 +1,6 @@ +FRAMEWORK_SEARCH_PATHS = "$(PODS_ROOT)/GoogleMaps/Frameworks" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/AFNetworking" "${PODS_ROOT}/Headers/Public/GoogleMaps" "${PODS_ROOT}/Headers/Public/GoogleMaps/GoogleMaps" "${PODS_ROOT}/Headers/Public/ISO8601DateFormatterValueTransformer" "${PODS_ROOT}/Headers/Public/RKValueTransformers" "${PODS_ROOT}/Headers/Public/RestKit" "${PODS_ROOT}/Headers/Public/RestKit/CoreData" "${PODS_ROOT}/Headers/Public/RestKit/Network" "${PODS_ROOT}/Headers/Public/RestKit/ObjectMapping" "${PODS_ROOT}/Headers/Public/RestKit/Support" "${PODS_ROOT}/Headers/Public/SOCKit" "${PODS_ROOT}/Headers/Public/TransitionKit" "${PODS_ROOT}/Headers/Public/Vendor/LibComponentLogging/Core" +OTHER_CFLAGS = $(inherited) -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/AFNetworking" -isystem "${PODS_ROOT}/Headers/Public/GoogleMaps" -isystem "${PODS_ROOT}/Headers/Public/GoogleMaps/GoogleMaps" -isystem "${PODS_ROOT}/Headers/Public/ISO8601DateFormatterValueTransformer" -isystem "${PODS_ROOT}/Headers/Public/RKValueTransformers" -isystem "${PODS_ROOT}/Headers/Public/RestKit" -isystem "${PODS_ROOT}/Headers/Public/RestKit/CoreData" -isystem "${PODS_ROOT}/Headers/Public/RestKit/Network" -isystem "${PODS_ROOT}/Headers/Public/RestKit/ObjectMapping" -isystem "${PODS_ROOT}/Headers/Public/RestKit/Support" -isystem "${PODS_ROOT}/Headers/Public/SOCKit" -isystem "${PODS_ROOT}/Headers/Public/TransitionKit" -isystem "${PODS_ROOT}/Headers/Public/Vendor/LibComponentLogging/Core" +OTHER_LDFLAGS = $(inherited) -ObjC -l"AFNetworking" -l"ISO8601DateFormatterValueTransformer" -l"RKValueTransformers" -l"RestKit" -l"SOCKit" -l"TransitionKit" -l"c++" -l"icucore" -l"z" -framework "AVFoundation" -framework "Accelerate" -framework "CFNetwork" -framework "CoreBluetooth" -framework "CoreData" -framework "CoreGraphics" -framework "CoreLocation" -framework "CoreText" -framework "GLKit" -framework "GoogleMaps" -framework "ImageIO" -framework "MobileCoreServices" -framework "OpenGLES" -framework "QuartzCore" -framework "Security" -framework "SystemConfiguration" +PODS_ROOT = ${SRCROOT}/Pods \ No newline at end of file diff --git a/Pods/Target Support Files/Pods/Pods.release.xcconfig b/Pods/Target Support Files/Pods/Pods.release.xcconfig new file mode 100644 index 0000000..f621237 --- /dev/null +++ b/Pods/Target Support Files/Pods/Pods.release.xcconfig @@ -0,0 +1,6 @@ +FRAMEWORK_SEARCH_PATHS = "$(PODS_ROOT)/GoogleMaps/Frameworks" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/AFNetworking" "${PODS_ROOT}/Headers/Public/GoogleMaps" "${PODS_ROOT}/Headers/Public/GoogleMaps/GoogleMaps" "${PODS_ROOT}/Headers/Public/ISO8601DateFormatterValueTransformer" "${PODS_ROOT}/Headers/Public/RKValueTransformers" "${PODS_ROOT}/Headers/Public/RestKit" "${PODS_ROOT}/Headers/Public/RestKit/CoreData" "${PODS_ROOT}/Headers/Public/RestKit/Network" "${PODS_ROOT}/Headers/Public/RestKit/ObjectMapping" "${PODS_ROOT}/Headers/Public/RestKit/Support" "${PODS_ROOT}/Headers/Public/SOCKit" "${PODS_ROOT}/Headers/Public/TransitionKit" "${PODS_ROOT}/Headers/Public/Vendor/LibComponentLogging/Core" +OTHER_CFLAGS = $(inherited) -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/AFNetworking" -isystem "${PODS_ROOT}/Headers/Public/GoogleMaps" -isystem "${PODS_ROOT}/Headers/Public/GoogleMaps/GoogleMaps" -isystem "${PODS_ROOT}/Headers/Public/ISO8601DateFormatterValueTransformer" -isystem "${PODS_ROOT}/Headers/Public/RKValueTransformers" -isystem "${PODS_ROOT}/Headers/Public/RestKit" -isystem "${PODS_ROOT}/Headers/Public/RestKit/CoreData" -isystem "${PODS_ROOT}/Headers/Public/RestKit/Network" -isystem "${PODS_ROOT}/Headers/Public/RestKit/ObjectMapping" -isystem "${PODS_ROOT}/Headers/Public/RestKit/Support" -isystem "${PODS_ROOT}/Headers/Public/SOCKit" -isystem "${PODS_ROOT}/Headers/Public/TransitionKit" -isystem "${PODS_ROOT}/Headers/Public/Vendor/LibComponentLogging/Core" +OTHER_LDFLAGS = $(inherited) -ObjC -l"AFNetworking" -l"ISO8601DateFormatterValueTransformer" -l"RKValueTransformers" -l"RestKit" -l"SOCKit" -l"TransitionKit" -l"c++" -l"icucore" -l"z" -framework "AVFoundation" -framework "Accelerate" -framework "CFNetwork" -framework "CoreBluetooth" -framework "CoreData" -framework "CoreGraphics" -framework "CoreLocation" -framework "CoreText" -framework "GLKit" -framework "GoogleMaps" -framework "ImageIO" -framework "MobileCoreServices" -framework "OpenGLES" -framework "QuartzCore" -framework "Security" -framework "SystemConfiguration" +PODS_ROOT = ${SRCROOT}/Pods \ No newline at end of file diff --git a/Pods/Target Support Files/RKValueTransformers/RKValueTransformers-Private.xcconfig b/Pods/Target Support Files/RKValueTransformers/RKValueTransformers-Private.xcconfig new file mode 100644 index 0000000..22f402f --- /dev/null +++ b/Pods/Target Support Files/RKValueTransformers/RKValueTransformers-Private.xcconfig @@ -0,0 +1,5 @@ +#include "RKValueTransformers.xcconfig" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/RKValueTransformers" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/AFNetworking" "${PODS_ROOT}/Headers/Public/GoogleMaps" "${PODS_ROOT}/Headers/Public/GoogleMaps/GoogleMaps" "${PODS_ROOT}/Headers/Public/ISO8601DateFormatterValueTransformer" "${PODS_ROOT}/Headers/Public/RKValueTransformers" "${PODS_ROOT}/Headers/Public/RestKit" "${PODS_ROOT}/Headers/Public/RestKit/CoreData" "${PODS_ROOT}/Headers/Public/RestKit/Network" "${PODS_ROOT}/Headers/Public/RestKit/ObjectMapping" "${PODS_ROOT}/Headers/Public/RestKit/Support" "${PODS_ROOT}/Headers/Public/SOCKit" "${PODS_ROOT}/Headers/Public/TransitionKit" "${PODS_ROOT}/Headers/Public/Vendor/LibComponentLogging/Core" +PODS_ROOT = ${SRCROOT} +SKIP_INSTALL = YES \ No newline at end of file diff --git a/Pods/Target Support Files/RKValueTransformers/RKValueTransformers-dummy.m b/Pods/Target Support Files/RKValueTransformers/RKValueTransformers-dummy.m new file mode 100644 index 0000000..792c92a --- /dev/null +++ b/Pods/Target Support Files/RKValueTransformers/RKValueTransformers-dummy.m @@ -0,0 +1,5 @@ +#import <Foundation/Foundation.h> +@interface PodsDummy_RKValueTransformers : NSObject +@end +@implementation PodsDummy_RKValueTransformers +@end diff --git a/Pods/Target Support Files/RKValueTransformers/RKValueTransformers-prefix.pch b/Pods/Target Support Files/RKValueTransformers/RKValueTransformers-prefix.pch new file mode 100644 index 0000000..aa992a4 --- /dev/null +++ b/Pods/Target Support Files/RKValueTransformers/RKValueTransformers-prefix.pch @@ -0,0 +1,4 @@ +#ifdef __OBJC__ +#import <UIKit/UIKit.h> +#endif + diff --git a/Pods/Target Support Files/RKValueTransformers/RKValueTransformers.xcconfig b/Pods/Target Support Files/RKValueTransformers/RKValueTransformers.xcconfig new file mode 100644 index 0000000..e69de29 diff --git a/Pods/Target Support Files/RestKit/RestKit-Private.xcconfig b/Pods/Target Support Files/RestKit/RestKit-Private.xcconfig new file mode 100644 index 0000000..38489c3 --- /dev/null +++ b/Pods/Target Support Files/RestKit/RestKit-Private.xcconfig @@ -0,0 +1,6 @@ +#include "RestKit.xcconfig" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/RestKit" "${PODS_ROOT}/Headers/Private/RestKit/CoreData" "${PODS_ROOT}/Headers/Private/RestKit/Network" "${PODS_ROOT}/Headers/Private/RestKit/ObjectMapping" "${PODS_ROOT}/Headers/Private/RestKit/Support" "${PODS_ROOT}/Headers/Private/Vendor/LibComponentLogging/Core" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/AFNetworking" "${PODS_ROOT}/Headers/Public/GoogleMaps" "${PODS_ROOT}/Headers/Public/GoogleMaps/GoogleMaps" "${PODS_ROOT}/Headers/Public/ISO8601DateFormatterValueTransformer" "${PODS_ROOT}/Headers/Public/RKValueTransformers" "${PODS_ROOT}/Headers/Public/RestKit" "${PODS_ROOT}/Headers/Public/RestKit/CoreData" "${PODS_ROOT}/Headers/Public/RestKit/Network" "${PODS_ROOT}/Headers/Public/RestKit/ObjectMapping" "${PODS_ROOT}/Headers/Public/RestKit/Support" "${PODS_ROOT}/Headers/Public/SOCKit" "${PODS_ROOT}/Headers/Public/TransitionKit" "${PODS_ROOT}/Headers/Public/Vendor/LibComponentLogging/Core" +OTHER_LDFLAGS = ${RESTKIT_OTHER_LDFLAGS} +PODS_ROOT = ${SRCROOT} +SKIP_INSTALL = YES \ No newline at end of file diff --git a/Pods/Target Support Files/RestKit/RestKit-dummy.m b/Pods/Target Support Files/RestKit/RestKit-dummy.m new file mode 100644 index 0000000..61870a2 --- /dev/null +++ b/Pods/Target Support Files/RestKit/RestKit-dummy.m @@ -0,0 +1,5 @@ +#import <Foundation/Foundation.h> +@interface PodsDummy_RestKit : NSObject +@end +@implementation PodsDummy_RestKit +@end diff --git a/Pods/Target Support Files/RestKit/RestKit-prefix.pch b/Pods/Target Support Files/RestKit/RestKit-prefix.pch new file mode 100644 index 0000000..2b52ab3 --- /dev/null +++ b/Pods/Target Support Files/RestKit/RestKit-prefix.pch @@ -0,0 +1,20 @@ +#ifdef __OBJC__ +#import <UIKit/UIKit.h> +#endif + +#if __has_include("RKCoreData.h") + #import <CoreData/CoreData.h> +#endif +#import <Availability.h> + +#define _AFNETWORKING_PIN_SSL_CERTIFICATES_ + +#if __IPHONE_OS_VERSION_MIN_REQUIRED + #import <SystemConfiguration/SystemConfiguration.h> + #import <MobileCoreServices/MobileCoreServices.h> + #import <Security/Security.h> +#else + #import <SystemConfiguration/SystemConfiguration.h> + #import <CoreServices/CoreServices.h> + #import <Security/Security.h> +#endif diff --git a/Pods/Target Support Files/RestKit/RestKit.xcconfig b/Pods/Target Support Files/RestKit/RestKit.xcconfig new file mode 100644 index 0000000..6422df2 --- /dev/null +++ b/Pods/Target Support Files/RestKit/RestKit.xcconfig @@ -0,0 +1 @@ +RESTKIT_OTHER_LDFLAGS = -framework "CFNetwork" -framework "CoreData" -framework "MobileCoreServices" -framework "Security" -framework "SystemConfiguration" \ No newline at end of file diff --git a/Pods/Target Support Files/SOCKit/SOCKit-Private.xcconfig b/Pods/Target Support Files/SOCKit/SOCKit-Private.xcconfig new file mode 100644 index 0000000..b24e77f --- /dev/null +++ b/Pods/Target Support Files/SOCKit/SOCKit-Private.xcconfig @@ -0,0 +1,5 @@ +#include "SOCKit.xcconfig" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/SOCKit" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/AFNetworking" "${PODS_ROOT}/Headers/Public/GoogleMaps" "${PODS_ROOT}/Headers/Public/GoogleMaps/GoogleMaps" "${PODS_ROOT}/Headers/Public/ISO8601DateFormatterValueTransformer" "${PODS_ROOT}/Headers/Public/RKValueTransformers" "${PODS_ROOT}/Headers/Public/RestKit" "${PODS_ROOT}/Headers/Public/RestKit/CoreData" "${PODS_ROOT}/Headers/Public/RestKit/Network" "${PODS_ROOT}/Headers/Public/RestKit/ObjectMapping" "${PODS_ROOT}/Headers/Public/RestKit/Support" "${PODS_ROOT}/Headers/Public/SOCKit" "${PODS_ROOT}/Headers/Public/TransitionKit" "${PODS_ROOT}/Headers/Public/Vendor/LibComponentLogging/Core" +PODS_ROOT = ${SRCROOT} +SKIP_INSTALL = YES \ No newline at end of file diff --git a/Pods/Target Support Files/SOCKit/SOCKit-dummy.m b/Pods/Target Support Files/SOCKit/SOCKit-dummy.m new file mode 100644 index 0000000..54b43ff --- /dev/null +++ b/Pods/Target Support Files/SOCKit/SOCKit-dummy.m @@ -0,0 +1,5 @@ +#import <Foundation/Foundation.h> +@interface PodsDummy_SOCKit : NSObject +@end +@implementation PodsDummy_SOCKit +@end diff --git a/Pods/Target Support Files/SOCKit/SOCKit-prefix.pch b/Pods/Target Support Files/SOCKit/SOCKit-prefix.pch new file mode 100644 index 0000000..aa992a4 --- /dev/null +++ b/Pods/Target Support Files/SOCKit/SOCKit-prefix.pch @@ -0,0 +1,4 @@ +#ifdef __OBJC__ +#import <UIKit/UIKit.h> +#endif + diff --git a/Pods/Target Support Files/SOCKit/SOCKit.xcconfig b/Pods/Target Support Files/SOCKit/SOCKit.xcconfig new file mode 100644 index 0000000..e69de29 diff --git a/Pods/Target Support Files/TransitionKit/TransitionKit-Private.xcconfig b/Pods/Target Support Files/TransitionKit/TransitionKit-Private.xcconfig new file mode 100644 index 0000000..39da371 --- /dev/null +++ b/Pods/Target Support Files/TransitionKit/TransitionKit-Private.xcconfig @@ -0,0 +1,5 @@ +#include "TransitionKit.xcconfig" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/TransitionKit" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/AFNetworking" "${PODS_ROOT}/Headers/Public/GoogleMaps" "${PODS_ROOT}/Headers/Public/GoogleMaps/GoogleMaps" "${PODS_ROOT}/Headers/Public/ISO8601DateFormatterValueTransformer" "${PODS_ROOT}/Headers/Public/RKValueTransformers" "${PODS_ROOT}/Headers/Public/RestKit" "${PODS_ROOT}/Headers/Public/RestKit/CoreData" "${PODS_ROOT}/Headers/Public/RestKit/Network" "${PODS_ROOT}/Headers/Public/RestKit/ObjectMapping" "${PODS_ROOT}/Headers/Public/RestKit/Support" "${PODS_ROOT}/Headers/Public/SOCKit" "${PODS_ROOT}/Headers/Public/TransitionKit" "${PODS_ROOT}/Headers/Public/Vendor/LibComponentLogging/Core" +PODS_ROOT = ${SRCROOT} +SKIP_INSTALL = YES \ No newline at end of file diff --git a/Pods/Target Support Files/TransitionKit/TransitionKit-dummy.m b/Pods/Target Support Files/TransitionKit/TransitionKit-dummy.m new file mode 100644 index 0000000..345483c --- /dev/null +++ b/Pods/Target Support Files/TransitionKit/TransitionKit-dummy.m @@ -0,0 +1,5 @@ +#import <Foundation/Foundation.h> +@interface PodsDummy_TransitionKit : NSObject +@end +@implementation PodsDummy_TransitionKit +@end diff --git a/Pods/Target Support Files/TransitionKit/TransitionKit-prefix.pch b/Pods/Target Support Files/TransitionKit/TransitionKit-prefix.pch new file mode 100644 index 0000000..aa992a4 --- /dev/null +++ b/Pods/Target Support Files/TransitionKit/TransitionKit-prefix.pch @@ -0,0 +1,4 @@ +#ifdef __OBJC__ +#import <UIKit/UIKit.h> +#endif + diff --git a/Pods/Target Support Files/TransitionKit/TransitionKit.xcconfig b/Pods/Target Support Files/TransitionKit/TransitionKit.xcconfig new file mode 100644 index 0000000..e69de29 diff --git a/Pods/TransitionKit/Code/TKEvent.h b/Pods/TransitionKit/Code/TKEvent.h new file mode 100644 index 0000000..abd2156 --- /dev/null +++ b/Pods/TransitionKit/Code/TKEvent.h @@ -0,0 +1,89 @@ +// +// TKEvent.h +// TransitionKit +// +// Created by Blake Watters on 3/17/13. +// Copyright (c) 2013 Blake Watters. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import <Foundation/Foundation.h> + +@class TKState, TKTransition; + +/** + The `TKEvent` class describes an event within a state machine that causes a transition between states. Each event has a descriptive name and specifies the state that the machine will transition into after the event has been fired. Events can optionally be constrained to a set of source states that the machine must be in for the event to fire. + */ +@interface TKEvent : NSObject <NSCoding, NSCopying> + +///------------------------ +/// @name Creating an Event +///------------------------ + +/** + Creates and returns a new event object with the given name, source states, and destination state. + + @param name The name for the event. + @param sourceStates An array of `TKState` objects specifying the source states that the machine must be in for the event to be permitted to fire. + @param destinationState The state that the state machine will transition into after the event has fired. + @return A newly created event object. + */ ++ (instancetype)eventWithName:(NSString *)name transitioningFromStates:(NSArray *)sourceStates toState:(TKState *)destinationState; + +///------------------------------ +/// @name Accessing Event Details +///------------------------------ + +@property (nonatomic, copy, readonly) NSString *name; + +/** + An optional array of states that the state machine must be in before the event is allowed to fire. + + If `nil`, then the event can be fired when the state machine is in any state. + */ +@property (nonatomic, copy, readonly) NSArray *sourceStates; + +/** + The state that the state machine will transition into after the event has fired. + + Cannot be `nil`. + */ +@property (nonatomic, strong, readonly) TKState *destinationState; + +///------------------------------ +/// @name Setting Callback Blocks +///------------------------------ + +/** + Sets a block to be executed in order to determines if an event should be fired. If the block returns `YES`, then the event will be permitted to fire. + + @param block The block to be executed to determine if the event can be fired. The block has a Boolean return value and accepts two arguments: the event that is being evaluated to determine if it can be fired and its associated transition. If the block returns `YES`, then the event can be fired. + */ +- (void)setShouldFireEventBlock:(BOOL (^)(TKEvent *event, TKTransition *transition))block; + +/** + Sets a block to be executed before an event is fired, while the state machine is still in the source state. + + @param block The block to be executed. The block has no return value and accepts two arguments: the event that is about to be fired and its associated transition. + */ +- (void)setWillFireEventBlock:(void (^)(TKEvent *event, TKTransition *transition))block; + +/** + Sets a block to be executed after an event is fired, when the state machine has transitioned into the destination state. + + @param block The block to be executed. The block has no return value and accepts two arguments: the event that has just been fired and its associated transition. + */ +- (void)setDidFireEventBlock:(void (^)(TKEvent *event, TKTransition *transition))block; + +@end diff --git a/Pods/TransitionKit/Code/TKEvent.m b/Pods/TransitionKit/Code/TKEvent.m new file mode 100644 index 0000000..8bbd728 --- /dev/null +++ b/Pods/TransitionKit/Code/TKEvent.m @@ -0,0 +1,101 @@ +// +// TKEvent.m +// TransitionKit +// +// Created by Blake Watters on 3/17/13. +// Copyright (c) 2013 Blake Watters. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "TKEvent.h" +#import "TKState.h" + +static NSString *TKDescribeSourceStates(NSArray *states) +{ + if (! [states count]) return @"any state"; + + NSMutableString *description = [NSMutableString string]; + [states enumerateObjectsUsingBlock:^(TKState *state, NSUInteger idx, BOOL *stop) { + NSString *separator = @""; + if (idx < [states count] - 1) separator = (idx == [states count] - 2) ? @" and " : @", "; + [description appendFormat:@"'%@'%@", state.name, separator]; + }]; + return description; +} + + +@interface TKEvent () +@property (nonatomic, copy, readwrite) NSString *name; +@property (nonatomic, copy, readwrite) NSArray *sourceStates; +@property (nonatomic, strong, readwrite) TKState *destinationState; +@property (nonatomic, copy) BOOL (^shouldFireEventBlock)(TKEvent *, TKTransition *); +@property (nonatomic, copy) void (^willFireEventBlock)(TKEvent *, TKTransition *); +@property (nonatomic, copy) void (^didFireEventBlock)(TKEvent *, TKTransition *); +@end + +@implementation TKEvent + ++ (instancetype)eventWithName:(NSString *)name transitioningFromStates:(NSArray *)sourceStates toState:(TKState *)destinationState +{ + if (! [name length]) [NSException raise:NSInvalidArgumentException format:@"The event name cannot be blank."]; + if (!destinationState) [NSException raise:NSInvalidArgumentException format:@"The destination state cannot be nil."]; + TKEvent *event = [self new]; + event.name = name; + event.sourceStates = sourceStates; + event.destinationState = destinationState; + return event; +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@"<%@:%p '%@' transitions from %@ to '%@'>", NSStringFromClass([self class]), self, self.name, TKDescribeSourceStates(self.sourceStates), self.destinationState.name]; +} + +#pragma mark - NSCoding + +- (id)initWithCoder:(NSCoder *)aDecoder +{ + self = [self init]; + if (!self) { + return nil; + } + + self.name = [aDecoder decodeObjectForKey:@"name"]; + self.sourceStates = [aDecoder decodeObjectForKey:@"sourceStates"]; + self.destinationState = [aDecoder decodeObjectForKey:@"destinationState"]; + return self; +} + +- (void)encodeWithCoder:(NSCoder *)aCoder +{ + [aCoder encodeObject:self.name forKey:@"name"]; + [aCoder encodeObject:self.sourceStates forKey:@"sourceStates"]; + [aCoder encodeObject:self.destinationState forKey:@"destinationState"]; +} + +#pragma mark - NSCopying + +- (id)copyWithZone:(NSZone *)zone +{ + TKEvent *copiedEvent = [[[self class] allocWithZone:zone] init]; + copiedEvent.name = self.name; + copiedEvent.sourceStates = self.sourceStates; + copiedEvent.destinationState = self.destinationState; + copiedEvent.shouldFireEventBlock = self.shouldFireEventBlock; + copiedEvent.willFireEventBlock = self.willFireEventBlock; + copiedEvent.didFireEventBlock = self.didFireEventBlock; + return copiedEvent; +} + +@end diff --git a/Pods/TransitionKit/Code/TKState.h b/Pods/TransitionKit/Code/TKState.h new file mode 100644 index 0000000..15a3dc8 --- /dev/null +++ b/Pods/TransitionKit/Code/TKState.h @@ -0,0 +1,83 @@ +// +// TKState.h +// TransitionKit +// +// Created by Blake Watters on 3/17/13. +// Copyright (c) 2013 Blake Watters. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import <Foundation/Foundation.h> + +@class TKTransition; + +/** + The `TKState` class defines a particular state with a state machine. Each state must have a unique name within the state machine in which it is used. + */ +@interface TKState : NSObject <NSCoding, NSCopying> + +///----------------------- +/// @name Creating a State +///----------------------- + +/** + Creates and returns a new state object with the specified name. + + @param name The name of the state. Cannot be blank. + @return A newly created state object with the specified name. + */ ++ (instancetype)stateWithName:(NSString *)name; + +///------------------------------------ +/// @name Accessing the Name of a State +///------------------------------------ + +/** + The name of the receiver. Cannot be `nil` and must be unique within the state machine that the receiver is added to. + */ +@property (nonatomic, copy, readonly) NSString *name; + +///---------------------------------- +/// @name Configuring Block Callbacks +///---------------------------------- + +/** + Sets a block to be executed before the state machine transitions into the state modeled by the receiver. + + @param block The block to executed before a state machine enters the receiver's state. The block has no return value and takes two arguments: the state object and a transition object modeling the state change. + */ +- (void)setWillEnterStateBlock:(void (^)(TKState *state, TKTransition *transition))block; + +/** + Sets a block to be executed after the state machine has transitioned into the state modeled by the receiver. + + @param block The block to executed after a state machine enters the receiver's state. The block has no return value and takes two arguments: the state object and a transition object modeling the state change. + */ +- (void)setDidEnterStateBlock:(void (^)(TKState *state, TKTransition *transition))block; + +/** + Sets a block to be executed before the state machine transitions out of the state modeled by the receiver. + + @param block The block to executed before a state machine exits the receiver's state. The block has no return value and takes two arguments: the state object and a transition object modeling the state change. + */ +- (void)setWillExitStateBlock:(void (^)(TKState *state, TKTransition *transition))block; + +/** + Sets a block to be executed after the state machine has transitioned out of the state modeled by the receiver. + + @param block The block to executed after a state machine exit the receiver's state. The block has no return value and takes two arguments: the state object and a transition object modeling the state change. + */ +- (void)setDidExitStateBlock:(void (^)(TKState *state, TKTransition *transition))block; + +@end diff --git a/Pods/TransitionKit/Code/TKState.m b/Pods/TransitionKit/Code/TKState.m new file mode 100644 index 0000000..1566339 --- /dev/null +++ b/Pods/TransitionKit/Code/TKState.m @@ -0,0 +1,77 @@ +// +// TKState.m +// TransitionKit +// +// Created by Blake Watters on 3/17/13. +// Copyright (c) 2013 Blake Watters. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "TKState.h" + +@interface TKState () +@property (nonatomic, copy, readwrite) NSString *name; +@property (nonatomic, copy) void (^willEnterStateBlock)(TKState *, TKTransition *); +@property (nonatomic, copy) void (^didEnterStateBlock)(TKState *, TKTransition *); +@property (nonatomic, copy) void (^willExitStateBlock)(TKState *, TKTransition *); +@property (nonatomic, copy) void (^didExitStateBlock)(TKState *, TKTransition *); +@end + +@implementation TKState + ++ (instancetype)stateWithName:(NSString *)name +{ + if (! [name length]) [NSException raise:NSInvalidArgumentException format:@"The `name` cannot be blank."]; + TKState *state = [TKState new]; + state.name = name; + return state; +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@"<%@:%p '%@'>", NSStringFromClass([self class]), self, self.name]; +} + +#pragma mark - NSCopying + +- (id)copyWithZone:(NSZone *)zone +{ + TKState *copiedState = [[[self class] allocWithZone:zone] init]; + copiedState.name = self.name; + copiedState.willEnterStateBlock = self.willEnterStateBlock; + copiedState.didEnterStateBlock = self.didEnterStateBlock; + copiedState.willExitStateBlock = self.willExitStateBlock; + copiedState.didExitStateBlock = self.didExitStateBlock; + return copiedState; +} + +#pragma mark - NSCoding + +- (id)initWithCoder:(NSCoder *)aDecoder +{ + self = [self init]; + if (!self) { + return nil; + } + + self.name = [aDecoder decodeObjectForKey:@"name"]; + return self; +} + +- (void)encodeWithCoder:(NSCoder *)aCoder +{ + [aCoder encodeObject:self.name forKey:@"name"]; +} + +@end diff --git a/Pods/TransitionKit/Code/TKStateMachine.h b/Pods/TransitionKit/Code/TKStateMachine.h new file mode 100644 index 0000000..cc6b3d9 --- /dev/null +++ b/Pods/TransitionKit/Code/TKStateMachine.h @@ -0,0 +1,245 @@ +// +// TKStateMachine.h +// TransitionKit +// +// Created by Blake Watters on 3/17/13. +// Copyright (c) 2013 Blake Watters. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import <Foundation/Foundation.h> + +@class TKEvent, TKState; + +/** + The `TKStateMachine` class provides an interface for modeling a state machine. The state machine supports the registration of an arbitrary number of states and events that trigger transitions between the states. + + ## Callback Sequence + + When a state machine is activated, the following callbacks are invoked: + + 1. Initial State: willEnterState - The block set with `setWillEnterStateBlock:` on the `initialState` is invoked. + 1. The `currentState` changes from `nil` to `initialState` + 1. Initial State: didEnterState - The block set with `setDidEnterStateBlock:` on the `initialState` is invoked. + + Each time an event is fired, the following callbacks are invoked: + + 1. Event: shouldFireEvent - The block set with `setShouldFireEventBlock:` on the event being fired is consulted to determine if the event can be fired. If `NO` is returned then the event is declined and no further callbacks are invoked + 1. Event: willFireEvent - The block set with `setWillFireEventBlock:` on the event being fired is invoked. + 1. Old State: willExitState - The block set with `setWillExitStateBlock:` on the outgoing state is invoked. + 1. New State: willEnterState - The block set with `setWillEnterStateBlock:` on the incoming state is invoked. + 1. The `currentState` changes from the old state to the new state. + 1. Old State: didExitState - The block set with `setDidExitStateBlock:` on the old state is invoked. + 1. New State: didEnterState - The block set with `setDidEnterStateBlock:` on the new current state is invoked. + 1. Event: didFireEvent - The block set with `setDidFireEventBlock:` on the event being fired is invoked. + 1. Notification: After the event has completed and all block callbacks + + ## Copying and Serialization Support + + The `TKStateMachine` class is both `NSCoding` and `NSCopying` compliant. When copied, a new inactive state machine instance is created with the same states, events, and initial state. All blocks associated with the events and states are copied. When archived, the current state, initial state, states, events and activation state is preserved. All block callbacks associated with the states and events become `nil`. + */ +@interface TKStateMachine : NSObject <NSCoding, NSCopying> + +///---------------------- +/// @name Managing States +///---------------------- + +/** + The set of states that have been added to the receiver. Each instance of the set is a `TKState` object. + */ +@property (nonatomic, readonly) NSSet *states; + +/** + The initial state of the receiver. + + When the machine is activated, it transitions into the initial state. + */ +@property (nonatomic, strong) TKState *initialState; + +/** + The current state of the receiver. + + When the machine is activated, the current state transitions from `nil` to the `initialState`. Subsequent state transitions are trigger by the firing of events. + + @see `fireEvent:error:` + */ +@property (nonatomic, strong, readonly) TKState *currentState; + +/** + Adds a state to the receiver. + + Before a state can be used in an event, it must be registered with the state machine. + + @param state The state to be added. + @raises TKStateMachineIsImmutableException Raised if an attempt is made to modify the state machine after it has been activated. + */ +- (void)addState:(TKState *)state; + +/** + Adds an array of state objects to the receiver. + + This is a convenience method whose implementation is equivalent to the following example code: + + for (TKState *state in arrayOfStates) { + [self addState:state]; + } + + @param arrayOfStates An array of `TKState` objects to be added to the receiver. + */ +- (void)addStates:(NSArray *)arrayOfStates; + +/** + Retrieves the state with the given name from the receiver. + + @param name The name of the state to retrieve. + @returns The state object with the given name or `nil` if it could not be found. + */ +- (TKState *)stateNamed:(NSString *)name; + +/** + Returns a Boolean value that indicates if the receiver is in the specified state. + + This is a convenience method whose functionality is equivalent to comparing the given state with the `currentState`. + + @param stateOrStateName A `TKState` object or an `NSString` object that identifies a state by name. The specified state is compared with the value of the `currentState` property. + @returns `YES` if the receiver is in the specified state, else `NO`. + @raises NSInvalidArgumentException Raised if an invalid object is given. + @raises NSInvalidArgumentException Raised if a string value is given that does not identify a registered state. + */ +- (BOOL)isInState:(id)stateOrStateName; + +///---------------------- +/// @name Managing Events +///---------------------- + +/** + The set of events that have been added to the receiver. Each instance of the set is a `TKEvent` object. + */ +@property (nonatomic, readonly) NSSet *events; + +/** + Adds an event to the receiver. + + The state objects references by the event must be registered with the receiver. + + @param event The event to be added. + @raises TKStateMachineIsImmutableException Raised if an attempt is made to modify the state machine after it has been activated. + @raises NSInternalInconsistencyException Raised if the given event references a `TKState` that has not been registered with the receiver. + */ +- (void)addEvent:(TKEvent *)event; + +/** + Adds an array of event objects to the receiver. + + This is a convenience method whose implementation is equivalent to the following example code: + + for (TKEvent *event in arrayOfEvents) { + [self addEvent:event]; + } + + @param arrayOfEvents An array of `TKEvent` objects to be added to the receiver. + */ +- (void)addEvents:(NSArray *)arrayOfEvents; + +/** + Retrieves the event with the given name from the receiver. + + @param name The name of the event to retrieve. + @returns The event object with the given name or `nil` if it could not be found. + */ +- (TKEvent *)eventNamed:(NSString *)name; + +///----------------------------------- +/// @name Activating the State Machine +///----------------------------------- + +/** + Activates the receiver by making it immutable and transitioning into the initial state. + + Once the state machine has been activated no further changes can be made to the registered events and states. Note that although callbacks will be dispatched for transition into the initial state upon activation, they will have a `nil` transition argument as no event has been fired. + */ +- (void)activate; + +/** + Returns a Boolean value that indicates if the receiver has been activated. + */ +- (BOOL)isActive; + +///-------------------- +/// @name Firing Events +///-------------------- + +/** + Returns a Boolean value that indicates if the specified event can be fired. + + @param eventOrEventName A `TKEvent` object or an `NSString` object that identifies an event by name. The source states of the specified event is compared with the current state of the receiver. If the `sourceStates` of the event is `nil`, then the event can be fired from any state. If the `sourcesStates` is not `nil`, then the event can only be fired if it includes the `currentState` of the receiver. + @return `YES` if the event can be fired, else `NO`. + */ +- (BOOL)canFireEvent:(id)eventOrEventName; + +/** + Fires an event to transition the state of the receiver. If the event fails to fire, then `NO` is returned and an error is set. + + If the receiver has not yet been activated, then the first event fired will activate it. If the specified transition is not permitted, then `NO` will be returned and an `TKInvalidTransitionError` will be created. If the `shouldFireEventBlock` of the specified event returns `NO`, then the event is declined, `NO` will be returned, and an `TKTransitionDeclinedError` will be created. + + @param eventOrEventName A `TKEvent` object or an `NSString` object that identifies an event by name. + @param userInfo An optional dictionary of user info to be delivered as part of the state transition. + @param error A pointer to an `NSError` object that will be set if the event fails to fire. + @return `YES` if the event is fired, else `NO`. + */ +- (BOOL)fireEvent:(id)eventOrEventName userInfo:(NSDictionary *)userInfo error:(NSError **)error; + +@end + +///---------------- +/// @name Constants +///---------------- + +/** + The domain for errors raised by TransitionKit. + */ +extern NSString *const TKErrorDomain; + +/** + A Notification posted when the `currentState` of a `TKStateMachine` object changes to a new value. + */ +extern NSString *const TKStateMachineDidChangeStateNotification; + +/** + A key in the `userInfo` dictionary of a `TKStateMachineDidChangeStateNotification` notification specifying the state of the machine before the transition occured. + */ +extern NSString *const TKStateMachineDidChangeStateOldStateUserInfoKey; + +/** + A key in the `userInfo` dictionary of a `TKStateMachineDidChangeStateNotification` notification specifying the state of the machine after the transition occured. + */ +extern NSString *const TKStateMachineDidChangeStateNewStateUserInfoKey; + +/** + A key in the `userInfo` dictionary of a `TKStateMachineDidChangeStateNotification` notification specifying the event that triggered the transition between states. + */ +extern NSString *const TKStateMachineDidChangeStateEventUserInfoKey; + +/** + An exception raised when an attempt is made to mutate an immutable `TKStateMachine` object. + */ +extern NSString *const TKStateMachineIsImmutableException; + +/** + Error Codes + */ +typedef enum { + TKInvalidTransitionError = 1000, // An invalid transition was attempted. + TKTransitionDeclinedError = 1001, // The transition was declined by the `shouldFireEvent` guard block. +} TKErrorCode; diff --git a/Pods/TransitionKit/Code/TKStateMachine.m b/Pods/TransitionKit/Code/TKStateMachine.m new file mode 100644 index 0000000..31a89fb --- /dev/null +++ b/Pods/TransitionKit/Code/TKStateMachine.m @@ -0,0 +1,304 @@ +// +// TKStateMachine.m +// TransitionKit +// +// Created by Blake Watters on 3/17/13. +// Copyright (c) 2013 Blake Watters. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "TKStateMachine.h" +#import "TKState.h" +#import "TKEvent.h" +#import "TKTransition.h" + +@interface TKEvent () +@property (nonatomic, copy) BOOL (^shouldFireEventBlock)(TKEvent *, TKTransition *); +@property (nonatomic, copy) void (^willFireEventBlock)(TKEvent *, TKTransition *); +@property (nonatomic, copy) void (^didFireEventBlock)(TKEvent *, TKTransition *); +@end + +@interface TKState () +@property (nonatomic, copy) void (^willEnterStateBlock)(TKState *, TKTransition *); +@property (nonatomic, copy) void (^didEnterStateBlock)(TKState *, TKTransition *); +@property (nonatomic, copy) void (^willExitStateBlock)(TKState *, TKTransition *); +@property (nonatomic, copy) void (^didExitStateBlock)(TKState *, TKTransition *); +@end + +NSString *const TKErrorDomain = @"org.blakewatters.TransitionKit.errors"; +NSString *const TKStateMachineDidChangeStateNotification = @"TKStateMachineDidChangeStateNotification"; +NSString *const TKStateMachineDidChangeStateOldStateUserInfoKey = @"old"; +NSString *const TKStateMachineDidChangeStateNewStateUserInfoKey = @"new"; +NSString *const TKStateMachineDidChangeStateEventUserInfoKey = @"event"; + +NSString *const TKStateMachineIsImmutableException = @"TKStateMachineIsImmutableException"; + +#define TKRaiseIfActive() \ + if ([self isActive]) [NSException raise:TKStateMachineIsImmutableException format:@"Unable to modify state machine: The state machine has already been activated."]; + +static NSString *TKQuoteString(NSString *string) +{ + return string ? [NSString stringWithFormat:@"'%@'", string] : nil; +} + +@interface TKStateMachine () +@property (nonatomic, strong) NSMutableSet *mutableStates; +@property (nonatomic, strong) NSMutableSet *mutableEvents; +@property (nonatomic, assign, getter = isActive) BOOL active; +@property (nonatomic, strong, readwrite) TKState *currentState; +@property (nonatomic, strong) NSRecursiveLock *lock; +@end + +@implementation TKStateMachine + ++ (NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key +{ + NSSet *keyPaths = [super keyPathsForValuesAffectingValueForKey:key]; + + if ([key isEqualToString:@"states"]) { + NSSet *affectingKey = [NSSet setWithObject:@"mutableStates"]; + keyPaths = [keyPaths setByAddingObjectsFromSet:affectingKey]; + return keyPaths; + } else if ([key isEqualToString:@"events"]) { + NSSet *affectingKey = [NSSet setWithObject:@"mutableEvents"]; + keyPaths = [keyPaths setByAddingObjectsFromSet:affectingKey]; + return keyPaths; + } + + return keyPaths; +} + +- (id)init +{ + self = [super init]; + if (self) { + self.mutableStates = [NSMutableSet set]; + self.mutableEvents = [NSMutableSet set]; + self.lock = [NSRecursiveLock new]; + } + return self; +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@"<%@:%p %ld States, %ld Events. currentState=%@, initialState='%@', isActive=%@>", + NSStringFromClass([self class]), self, (unsigned long) [self.mutableStates count], (unsigned long) [self.mutableEvents count], + TKQuoteString(self.currentState.name), self.initialState.name, self.isActive ? @"YES" : @"NO"]; +} + +- (void)setInitialState:(TKState *)initialState +{ + TKRaiseIfActive(); + _initialState = initialState; +} + +- (NSSet *)states +{ + return [NSSet setWithSet:self.mutableStates]; +} + +- (void)addState:(TKState *)state +{ + TKRaiseIfActive(); + if (! [state isKindOfClass:[TKState class]]) [NSException raise:NSInvalidArgumentException format:@"Expected a `TKState` object, instead got a `%@` (%@)", [state class], state]; + if ([self stateNamed: state.name]) [NSException raise:NSInvalidArgumentException format:@"State with name `%@` already exists", state.name]; + + if (self.initialState == nil) self.initialState = state; + [self.mutableStates addObject:state]; +} + +- (void)addStates:(NSArray *)arrayOfStates +{ + TKRaiseIfActive(); + for (TKState *state in arrayOfStates) { + [self addState:state]; + } +} + +- (TKState *)stateNamed:(NSString *)name +{ + for (TKState *state in self.mutableStates) { + if ([state.name isEqualToString:name]) return state; + } + return nil; +} + +- (BOOL)isInState:(id)stateOrStateName +{ + if (! [stateOrStateName isKindOfClass:[TKState class]] && ![stateOrStateName isKindOfClass:[NSString class]]) [NSException raise:NSInvalidArgumentException format:@"Expected a `TKState` object or `NSString` object specifying the name of a state, instead got a `%@` (%@)", [stateOrStateName class], stateOrStateName]; + TKState *state = [stateOrStateName isKindOfClass:[TKState class]] ? stateOrStateName : [self stateNamed:stateOrStateName]; + if (! state) [NSException raise:NSInvalidArgumentException format:@"Cannot find a State named '%@'", stateOrStateName]; + return [self.currentState isEqual:state]; +} + +- (NSSet *)events +{ + return [NSSet setWithSet:self.mutableEvents]; +} + +- (void)addEvent:(TKEvent *)event +{ + TKRaiseIfActive(); + if (! event) [NSException raise:NSInvalidArgumentException format:@"Cannot add a `nil` event to the state machine."]; + if (event.sourceStates) { + for (TKState *state in event.sourceStates) { + if (! [self.mutableStates containsObject:state]) { + [NSException raise:NSInternalInconsistencyException format:@"Cannot add event '%@' to the state machine: the event references a state '%@', which has not been added to the state machine.", event.name, state.name]; + } + } + } + if (! [self.mutableStates containsObject:event.destinationState]) [NSException raise:NSInternalInconsistencyException format:@"Cannot add event '%@' to the state machine: the event references a state '%@', which has not been added to the state machine.", event.name, event.destinationState.name]; + [self.mutableEvents addObject:event]; +} + +- (void)addEvents:(NSArray *)arrayOfEvents +{ + TKRaiseIfActive(); + for (TKEvent *event in arrayOfEvents) { + [self addEvent:event]; + } +} + +- (TKEvent *)eventNamed:(NSString *)name +{ + for (TKEvent *event in self.mutableEvents) { + if ([event.name isEqualToString:name]) return event; + } + return nil; +} + +- (void)activate +{ + if (self.isActive) [NSException raise:NSInternalInconsistencyException format:@"The state machine has already been activated."]; + [self.lock lock]; + self.active = YES; + + // Dispatch callbacks to establish initial state + if (self.initialState.willEnterStateBlock) self.initialState.willEnterStateBlock(self.initialState, nil); + self.currentState = self.initialState; + if (self.initialState.didEnterStateBlock) self.initialState.didEnterStateBlock(self.initialState, nil); + [self.lock unlock]; +} + +- (BOOL)canFireEvent:(id)eventOrEventName +{ + if (! [eventOrEventName isKindOfClass:[TKEvent class]] && ![eventOrEventName isKindOfClass:[NSString class]]) [NSException raise:NSInvalidArgumentException format:@"Expected a `TKEvent` object or `NSString` object specifying the name of an event, instead got a `%@` (%@)", [eventOrEventName class], eventOrEventName]; + TKEvent *event = [eventOrEventName isKindOfClass:[TKEvent class]] ? eventOrEventName : [self eventNamed:eventOrEventName]; + if (! event) [NSException raise:NSInvalidArgumentException format:@"Cannot find an Event named '%@'", eventOrEventName]; + return [event.sourceStates containsObject:self.currentState]; +} + +- (BOOL)fireEvent:(id)eventOrEventName userInfo:(NSDictionary *)userInfo error:(NSError *__autoreleasing *)error +{ + [self.lock lock]; + if (! self.isActive) [self activate]; + if (! [eventOrEventName isKindOfClass:[TKEvent class]] && ![eventOrEventName isKindOfClass:[NSString class]]) [NSException raise:NSInvalidArgumentException format:@"Expected a `TKEvent` object or `NSString` object specifying the name of an event, instead got a `%@` (%@)", [eventOrEventName class], eventOrEventName]; + TKEvent *event = [eventOrEventName isKindOfClass:[TKEvent class]] ? eventOrEventName : [self eventNamed:eventOrEventName]; + if (! event) [NSException raise:NSInvalidArgumentException format:@"Cannot find an Event named '%@'", eventOrEventName]; + + // Check that this transition is permitted + if (event.sourceStates != nil && ![event.sourceStates containsObject:self.currentState]) { + NSString *failureReason = [NSString stringWithFormat:@"An attempt was made to fire the '%@' event while in the '%@' state, but the event can only be fired from the following states: %@", event.name, self.currentState.name, [[event.sourceStates valueForKey:@"name"] componentsJoinedByString:@", "]]; + NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: @"The event cannot be fired from the current state.", NSLocalizedFailureReasonErrorKey: failureReason }; + if (error) *error = [NSError errorWithDomain:TKErrorDomain code:TKInvalidTransitionError userInfo:userInfo]; + [self.lock unlock]; + return NO; + } + + TKTransition *transition = [TKTransition transitionForEvent:event fromState:self.currentState inStateMachine:self userInfo:userInfo]; + if (event.shouldFireEventBlock) { + if (! event.shouldFireEventBlock(event, transition)) { + NSString *failureReason = [NSString stringWithFormat:@"An attempt to fire the '%@' event was declined because `shouldFireEventBlock` returned `NO`.", event.name]; + NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: @"The event declined to be fired.", NSLocalizedFailureReasonErrorKey: failureReason }; + if (error) *error = [NSError errorWithDomain:TKErrorDomain code:TKTransitionDeclinedError userInfo:userInfo]; + [self.lock unlock]; + return NO; + } + } + + TKState *oldState = self.currentState; + TKState *newState = event.destinationState; + + if (event.willFireEventBlock) event.willFireEventBlock(event, transition); + + if (oldState.willExitStateBlock) oldState.willExitStateBlock(oldState, transition); + if (newState.willEnterStateBlock) newState.willEnterStateBlock(newState, transition); + self.currentState = newState; + if (oldState.didExitStateBlock) oldState.didExitStateBlock(oldState, transition); + if (newState.didEnterStateBlock) newState.didEnterStateBlock(newState, transition); + + if (event.didFireEventBlock) event.didFireEventBlock(event, transition); + [self.lock unlock]; + + NSMutableDictionary *notificationInfo = [userInfo mutableCopy] ?: [NSMutableDictionary dictionary]; + [notificationInfo addEntriesFromDictionary:@{ TKStateMachineDidChangeStateOldStateUserInfoKey: oldState, + TKStateMachineDidChangeStateNewStateUserInfoKey: newState, + TKStateMachineDidChangeStateEventUserInfoKey: event }]; + [[NSNotificationCenter defaultCenter] postNotificationName:TKStateMachineDidChangeStateNotification object:self userInfo:notificationInfo]; + + return YES; +} + +#pragma mark - NSCoding + +- (id)initWithCoder:(NSCoder *)aDecoder +{ + self = [self init]; + if (!self) { + return nil; + } + + self.initialState = [aDecoder decodeObjectForKey:@"initialState"]; + self.currentState =[aDecoder decodeObjectForKey:@"currentState"]; + self.mutableStates = [[aDecoder decodeObjectForKey:@"states"] mutableCopy]; + self.mutableEvents = [[aDecoder decodeObjectForKey:@"events"] mutableCopy]; + self.active = [aDecoder decodeBoolForKey:@"isActive"]; + return self; +} + +- (void)encodeWithCoder:(NSCoder *)aCoder +{ + [aCoder encodeObject:self.initialState forKey:@"initialState"]; + [aCoder encodeObject:self.currentState forKey:@"currentState"]; + [aCoder encodeObject:self.states forKey:@"states"]; + [aCoder encodeObject:self.events forKey:@"events"]; + [aCoder encodeBool:self.isActive forKey:@"isActive"]; +} + +#pragma mark - NSCopying + +- (id)copyWithZone:(NSZone *)zone +{ + TKStateMachine *copiedStateMachine = [[[self class] allocWithZone:zone] init]; + copiedStateMachine.active = NO; + copiedStateMachine.currentState = nil; + copiedStateMachine.initialState = self.initialState; + + for (TKState *state in self.states) { + [copiedStateMachine addState:[state copy]]; + } + + for (TKEvent *event in self.events) { + NSMutableArray *sourceStates = [NSMutableArray arrayWithCapacity:[event.sourceStates count]]; + for (TKState *sourceState in event.sourceStates) { + [sourceStates addObject:[copiedStateMachine stateNamed:sourceState.name]]; + } + TKState *destinationState = [copiedStateMachine stateNamed:event.destinationState.name]; + TKEvent *copiedEvent = [TKEvent eventWithName:event.name transitioningFromStates:sourceStates toState:destinationState]; + [copiedStateMachine addEvent:copiedEvent]; + } + return copiedStateMachine; +} + +@end diff --git a/Pods/TransitionKit/Code/TKTransition.h b/Pods/TransitionKit/Code/TKTransition.h new file mode 100644 index 0000000..91c5aa6 --- /dev/null +++ b/Pods/TransitionKit/Code/TKTransition.h @@ -0,0 +1,73 @@ +// +// TKTransition.h +// TransitionKit +// +// Created by Blake Watters on 10/11/13. +// Copyright (c) 2013 Blake Watters. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import <Foundation/Foundation.h> + +@class TKEvent, TKState, TKStateMachine; + +/** + The `TKTransition` class models a state change in response to an event firing within a state machine. It encapsulates all details about the change and is yielded as an argument to all block callbacks within TransitionKit. The optional dictionary of `userInfo` can be used to broadcast arbitrary data across callbacks. + */ +@interface TKTransition : NSObject + +///---------------------------- +/// @name Creating a Transition +///---------------------------- + +/** + Creates and returns a new transition object describing a state change occuring within a state machine in response to the firing of an event. + + @param event The event being fired that is causing the transition to occur. + @param sourceState The state of the machine when the event was fired. + @param stateMachine The state machine in which the transition is occurirng. + @param userInfo An optional dictionary of user info supplied with the event when it was fired. + */ ++ (instancetype)transitionForEvent:(TKEvent *)event fromState:(TKState *)sourceState inStateMachine:(TKStateMachine *)stateMachine userInfo:(NSDictionary *)userInfo; + +///----------------------------------- +/// @name Accessing Transition Details +///----------------------------------- + +/** + The event that was fired, causing the transition to occur. + */ +@property (nonatomic, strong, readonly) TKEvent *event; + +/** + The state of the state machine when the transition starts. + */ +@property (nonatomic, strong, readonly) TKState *sourceState; + +/** + The state of the state machine after the transition finishes. + */ +@property (nonatomic, strong, readonly) TKState *destinationState; + +/** + The state machine in which the transition is occurring. + */ +@property (nonatomic, strong, readonly) TKStateMachine *stateMachine; + +/** + An optional dictionary of user info supplied with the event when fired. + */ +@property (nonatomic, copy, readonly) NSDictionary *userInfo; + +@end diff --git a/Pods/TransitionKit/Code/TKTransition.m b/Pods/TransitionKit/Code/TKTransition.m new file mode 100644 index 0000000..21cb35c --- /dev/null +++ b/Pods/TransitionKit/Code/TKTransition.m @@ -0,0 +1,49 @@ +// +// TKTransition.m +// TransitionKit +// +// Created by Blake Watters on 10/11/13. +// Copyright (c) 2013 Blake Watters. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "TKTransition.h" +#import "TKEvent.h" + +@interface TKTransition () + +@property (nonatomic, strong, readwrite) TKEvent *event; +@property (nonatomic, strong, readwrite) TKState *sourceState; +@property (nonatomic, strong, readwrite) TKStateMachine *stateMachine; +@property (nonatomic, copy, readwrite) NSDictionary *userInfo; +@end + +@implementation TKTransition + ++ (instancetype)transitionForEvent:(TKEvent *)event fromState:(TKState *)sourceState inStateMachine:(TKStateMachine *)stateMachine userInfo:(NSDictionary *)userInfo +{ + TKTransition *transition = [self new]; + transition.event = event; + transition.sourceState = sourceState; + transition.stateMachine = stateMachine; + transition.userInfo = userInfo; + return transition; +} + +- (TKState *)destinationState +{ + return self.event.destinationState; +} + +@end diff --git a/Pods/TransitionKit/Code/TransitionKit.h b/Pods/TransitionKit/Code/TransitionKit.h new file mode 100644 index 0000000..2505ad9 --- /dev/null +++ b/Pods/TransitionKit/Code/TransitionKit.h @@ -0,0 +1,29 @@ +// +// TransitionKit.h +// TransitionKit +// +// Created by Blake Watters on 3/17/13. +// Copyright (c) 2013 Blake Watters. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#ifndef TransitionKit_TransitionKit_h +#define TransitionKit_TransitionKit_h + +#import "TKStateMachine.h" +#import "TKEvent.h" +#import "TKState.h" +#import "TKTransition.h" + +#endif diff --git a/Pods/TransitionKit/LICENSE b/Pods/TransitionKit/LICENSE new file mode 100644 index 0000000..eb8d4bc --- /dev/null +++ b/Pods/TransitionKit/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2009-2012 The RestKit Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Pods/TransitionKit/README.md b/Pods/TransitionKit/README.md new file mode 100644 index 0000000..299f983 --- /dev/null +++ b/Pods/TransitionKit/README.md @@ -0,0 +1,126 @@ +TransitionKit +============= + +[![Build Status](https://travis-ci.org/blakewatters/TransitionKit.png?branch=master,development)](https://travis-ci.org/blakewatters/TransitionKit) +![Pod Version](https://cocoapod-badges.herokuapp.com/v/TransitionKit/badge.png) +![Pod Platform](https://cocoapod-badges.herokuapp.com/p/TransitionKit/badge.png) + +**A simple, elegantly designed block based API for implementing State Machines in Objective-C** + +TransitionKit is a small Cocoa library that provides an API for implementing a state machine in Objective C. It is full-featured, completely documented, and very thoroughly unit tested. State machines are a great way to manage complexity in your application and TransitionKit provides you with an elegant API for implementing state machines in your next iOS or Mac OS X application. + +### Features + +* Supports an arbitrary number of States and Events. +* States and Events support a thorough set of block based callbacks for responding to state transitions. +* States, Events, and State Machines are NSCopying and NSCoding compliant, enabling easy integration with archiving and copying in your custom classes. +* Strongly enforced. The state machine includes numerous runtime checks for misconfigurations, making it easy to debug and trust your state machines. +* Transitions support the inclusion of arbitrary user data via a `userInfo` dictionary, making it easy to broadcast metadata across callbacks. +* Completely Documented. The entire library is marked up with Appledoc. +* Thorougly unit tested. You know it works and can make changes with confidence. +* Lightweight. TransitionKit has no dependencies beyond the Foundation library and works on iOS and Mac OS X. + +## Installation via CocoaPods + +The recommended approach for installing TransitionKit is via the [CocoaPods](http://cocoapods.org/) package manager, as it provides flexible dependency management and dead simple installation. For best results, it is recommended that you install via CocoaPods **>= 0.16.0** using Git **>= 1.8.0** installed via Homebrew. + +Install CocoaPods if not already available: + +``` bash +$ [sudo] gem install cocoapods +$ pod setup +``` + +Change to the directory of your Xcode project, and Create and Edit your Podfile and add TransitionKit: + +``` bash +$ cd /path/to/MyProject +$ touch Podfile +$ edit Podfile +platform :ios, '5.0' +# Or platform :osx, '10.7' +pod 'TransitionKit', '~> 2.0.0' +``` + +Install into your project: + +``` bash +$ pod install +``` + +Open your project in Xcode from the .xcworkspace file (not the usual project file) + +``` bash +$ open MyProject.xcworkspace +``` + +## Examples + +#### Simple Example + +The following example is a simple state machine that models the state of a Message in an Inbox. + +```objc +TKStateMachine *inboxStateMachine = [TKStateMachine new]; + +TKState *unread = [TKState stateWithName:@"Unread"]; +[unread setDidEnterStateBlock:^(TKState *state, TKTransition *transition) { + [self incrementUnreadCount]; +}]; +TKState *read = [TKState stateWithName:@"Read"]; +[read setDidExitStateBlock:^(TKState *state, TKTransition *transition) { + [self decrementUnreadCount]; +}]; +TKState *deleted = [TKState stateWithName:@"Deleted"]; +[deleted setDidEnterStateBlock:^(TKState *state, TKTransition *transition) { + [self moveMessageToTrash]; +}]; + +[inboxStateMachine addStates:@[ unread, read, deleted ]]; +inboxStateMachine.initialState = unread; + +TKEvent *viewMessage = [TKEvent eventWithName:@"View Message" transitioningFromStates:@[ unread ] toState:read]; +TKEvent *deleteMessage = [TKEvent eventWithName:@"Delete Message" transitioningFromStates:@[ read, unread ] toState:deleted]; +TKEvent *markAsUnread = [TKEvent eventWithName:@"Mark as Unread" transitioningFromStates:@[ read, deleted ] toState:unread]; + +[inboxStateMachine addEvents:@[ viewMessage, deleteMessage, markAsUnread ]]; + +// Activate the state machine +[inboxStateMachine activate]; + +[inboxStateMachine isInState:@"Unread"]; // YES, the initial state + +// Fire some events +NSDictionary *userInfo = nil; +NSError *error = nil; +BOOL success = [inboxStateMachine fireEvent:@"View Message" userInfo:userInfo error:&error]; // YES +success = [inboxStateMachine fireEvent:@"Delete Message" userInfo:userInfo error:&error]; // YES +success = [inboxStateMachine fireEvent:@"Mark as Unread" userInfo:userInfo error:&error]; // YES + +success = [inboxStateMachine canFireEvent:@"Mark as Unread"]; // NO + +// Error. Cannot mark an Unread message as Unread +success = [inboxStateMachine fireEvent:@"Mark as Unread" userInfo:nil error:&error]; // NO + +// error is an TKInvalidTransitionError with a descriptive error message and failure reason +``` + +## Unit Tests + +TransitionKit is tested using the [Kiwi](https://github.com/allending/Kiwi) BDD library. In order to run the tests, you must do the following: + +1. Install the dependencies via CocoaPods: `pod install` +1. Open the workspace: `open TransitionKit.xcworkspace` +1. Run the specs via the **Product** menu > **Test** + +## Contact + +Blake Watters + +- http://github.com/blakewatters +- http://twitter.com/blakewatters +- blakewatters@gmail.com + +## License + +TransitionKit is available under the Apache 2 License. See the LICENSE file for more info. diff --git a/TalkinToTheNet/TalkinToTheNet.xcodeproj/Podfile b/TalkinToTheNet/TalkinToTheNet.xcodeproj/Podfile new file mode 100644 index 0000000..0044fcc --- /dev/null +++ b/TalkinToTheNet/TalkinToTheNet.xcodeproj/Podfile @@ -0,0 +1 @@ +pod 'GoogleMaps', '~> 1.10' \ No newline at end of file diff --git a/TalkinToTheNet/TalkinToTheNet.xcodeproj/project.pbxproj b/TalkinToTheNet/TalkinToTheNet.xcodeproj/project.pbxproj index ee35a70..a104e64 100644 --- a/TalkinToTheNet/TalkinToTheNet.xcodeproj/project.pbxproj +++ b/TalkinToTheNet/TalkinToTheNet.xcodeproj/project.pbxproj @@ -9,7 +9,6 @@ /* Begin PBXBuildFile section */ 8D7DCD4B1BAF859400A92AD2 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 8D7DCD4A1BAF859400A92AD2 /* main.m */; }; 8D7DCD4E1BAF859400A92AD2 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 8D7DCD4D1BAF859400A92AD2 /* AppDelegate.m */; }; - 8D7DCD511BAF859400A92AD2 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8D7DCD501BAF859400A92AD2 /* ViewController.m */; }; 8D7DCD541BAF859400A92AD2 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8D7DCD521BAF859400A92AD2 /* Main.storyboard */; }; 8D7DCD561BAF859400A92AD2 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 8D7DCD551BAF859400A92AD2 /* Assets.xcassets */; }; 8D7DCD591BAF859400A92AD2 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8D7DCD571BAF859400A92AD2 /* LaunchScreen.storyboard */; }; @@ -20,8 +19,6 @@ 8D7DCD4A1BAF859400A92AD2 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; }; 8D7DCD4C1BAF859400A92AD2 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; }; 8D7DCD4D1BAF859400A92AD2 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; }; - 8D7DCD4F1BAF859400A92AD2 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = "<group>"; }; - 8D7DCD501BAF859400A92AD2 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = "<group>"; }; 8D7DCD531BAF859400A92AD2 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; }; 8D7DCD551BAF859400A92AD2 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; }; 8D7DCD581BAF859400A92AD2 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; }; @@ -60,8 +57,6 @@ children = ( 8D7DCD4C1BAF859400A92AD2 /* AppDelegate.h */, 8D7DCD4D1BAF859400A92AD2 /* AppDelegate.m */, - 8D7DCD4F1BAF859400A92AD2 /* ViewController.h */, - 8D7DCD501BAF859400A92AD2 /* ViewController.m */, 8D7DCD521BAF859400A92AD2 /* Main.storyboard */, 8D7DCD551BAF859400A92AD2 /* Assets.xcassets */, 8D7DCD571BAF859400A92AD2 /* LaunchScreen.storyboard */, @@ -149,7 +144,6 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 8D7DCD511BAF859400A92AD2 /* ViewController.m in Sources */, 8D7DCD4E1BAF859400A92AD2 /* AppDelegate.m in Sources */, 8D7DCD4B1BAF859400A92AD2 /* main.m in Sources */, ); @@ -300,6 +294,7 @@ 8D7DCD5F1BAF859400A92AD2 /* Release */, ); defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; diff --git a/TalkinToTheNet/TalkinToTheNet/Base.lproj/Main.storyboard b/TalkinToTheNet/TalkinToTheNet/Base.lproj/Main.storyboard index f56d2f3..fa78971 100644 --- a/TalkinToTheNet/TalkinToTheNet/Base.lproj/Main.storyboard +++ b/TalkinToTheNet/TalkinToTheNet/Base.lproj/Main.storyboard @@ -1,13 +1,59 @@ <?xml version="1.0" encoding="UTF-8" standalone="no"?> -<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="6211" systemVersion="14A298i" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r"> +<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="8191" systemVersion="14F27" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r"> <dependencies> - <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6204"/> + <deployment identifier="iOS"/> + <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="8154"/> </dependencies> <scenes> + <!--Root View Controller--> + <scene sceneID="4al-on-4qr"> + <objects> + <tableViewController id="0f6-go-xWq" sceneMemberID="viewController"> + <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="28" sectionFooterHeight="28" id="TgI-ue-xkH"> + <rect key="frame" x="0.0" y="0.0" width="600" height="600"/> + <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> + <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/> + <prototypes> + <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" id="rMD-At-qbI"> + <rect key="frame" x="0.0" y="92" width="600" height="44"/> + <autoresizingMask key="autoresizingMask"/> + <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="rMD-At-qbI" id="sPN-HK-E55"> + <rect key="frame" x="0.0" y="0.0" width="600" height="43"/> + <autoresizingMask key="autoresizingMask"/> + </tableViewCellContentView> + </tableViewCell> + </prototypes> + <connections> + <outlet property="dataSource" destination="0f6-go-xWq" id="13F-Q9-YV3"/> + <outlet property="delegate" destination="0f6-go-xWq" id="tma-1y-Sc1"/> + </connections> + </tableView> + <navigationItem key="navigationItem" title="Root View Controller" id="C43-SX-Jy0"/> + </tableViewController> + <placeholder placeholderIdentifier="IBFirstResponder" id="agW-z7-dGz" userLabel="First Responder" sceneMemberID="firstResponder"/> + </objects> + <point key="canvasLocation" x="-198" y="568"/> + </scene> + <!--Navigation Controller--> + <scene sceneID="26I-hh-j31"> + <objects> + <navigationController id="kcb-as-tzd" sceneMemberID="viewController"> + <navigationBar key="navigationBar" contentMode="scaleToFill" id="P1O-r1-iER"> + <rect key="frame" x="0.0" y="0.0" width="320" height="44"/> + <autoresizingMask key="autoresizingMask"/> + </navigationBar> + <connections> + <segue destination="0f6-go-xWq" kind="relationship" relationship="rootViewController" id="1Df-B9-c1k"/> + </connections> + </navigationController> + <placeholder placeholderIdentifier="IBFirstResponder" id="N5f-wI-l6L" userLabel="First Responder" sceneMemberID="firstResponder"/> + </objects> + <point key="canvasLocation" x="-1018" y="567"/> + </scene> <!--View Controller--> <scene sceneID="tne-QT-ifu"> <objects> - <viewController id="BYZ-38-t0r" customClass="ViewController" customModuleProvider="" sceneMemberID="viewController"> + <viewController id="BYZ-38-t0r" customClass="ViewController" sceneMemberID="viewController"> <layoutGuides> <viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/> <viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/> @@ -20,6 +66,7 @@ </viewController> <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/> </objects> + <point key="canvasLocation" x="501" y="568"/> </scene> </scenes> </document> diff --git a/TalkinToTheNet/TalkinToTheNet/Podfile b/TalkinToTheNet/TalkinToTheNet/Podfile new file mode 100644 index 0000000..0044fcc --- /dev/null +++ b/TalkinToTheNet/TalkinToTheNet/Podfile @@ -0,0 +1 @@ +pod 'GoogleMaps', '~> 1.10' \ No newline at end of file diff --git a/TalkinToTheNet/TalkinToTheNet/ViewController.h b/TalkinToTheNet/TalkinToTheNet/ViewController.h deleted file mode 100644 index 8113a85..0000000 --- a/TalkinToTheNet/TalkinToTheNet/ViewController.h +++ /dev/null @@ -1,15 +0,0 @@ -// -// ViewController.h -// TalkinToTheNet -// -// Created by Michael Kavouras on 9/20/15. -// Copyright © 2015 Mike Kavouras. All rights reserved. -// - -#import <UIKit/UIKit.h> - -@interface ViewController : UIViewController - - -@end - diff --git a/TalkinToTheNet/TalkinToTheNet/ViewController.m b/TalkinToTheNet/TalkinToTheNet/ViewController.m deleted file mode 100644 index cbefa29..0000000 --- a/TalkinToTheNet/TalkinToTheNet/ViewController.m +++ /dev/null @@ -1,27 +0,0 @@ -// -// ViewController.m -// TalkinToTheNet -// -// Created by Michael Kavouras on 9/20/15. -// Copyright © 2015 Mike Kavouras. All rights reserved. -// - -#import "ViewController.h" - -@interface ViewController () - -@end - -@implementation ViewController - -- (void)viewDidLoad { - [super viewDidLoad]; - // Do any additional setup after loading the view, typically from a nib. -} - -- (void)didReceiveMemoryWarning { - [super didReceiveMemoryWarning]; - // Dispose of any resources that can be recreated. -} - -@end