diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..137985c
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,35 @@
+# OS X Finder
+.DS_Store
+
+# Xcode per-user config
+*.mode1
+*.mode1v3
+*.mode2v3
+*.perspective
+*.perspectivev3
+*.pbxuser
+xcuserdata
+*.xccheckout
+
+# Build products
+build/
+*.o
+*.LinkFileList
+*.hmap
+
+# Automatic backup files
+*~.nib/
+*.swp
+*~
+*.dat
+*.dep
+
+# AppCode specific files
+.idea/
+*.iml
+
+# Cucumber console history
+*.irb-history
+
+# Python specific files
+*.pyc
diff --git a/AppDelegate.swift b/AppDelegate.swift
deleted file mode 100644
index 24bc691..0000000
--- a/AppDelegate.swift
+++ /dev/null
@@ -1,53 +0,0 @@
-//
-// AppDelegate.swift
-// Dindr
-//
-// Created by lsecrease on 8/9/15.
-// Copyright (c) 2015 ImagineME. All rights reserved.
-//
-
-import UIKit
-
-
-@UIApplicationMain
-class AppDelegate: UIResponder, UIApplicationDelegate {
-
- var window: UIWindow?
-
-
- func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
-
- Parse.enableLocalDatastore()
-
- // Parse App ID
- Parse.setApplicationId("0rubnb7O4htTp2ebMAM2KXnPazFxilATgmZvKLde", clientKey: "0shAOvyF065qlhgquNoHwSlu7dLOtv6vavggY8fp")
-
- // Override point for customization after application launch.
- return true
- }
-
- func applicationWillResignActive(application: UIApplication) {
- // 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.
- }
-
- func applicationDidEnterBackground(application: UIApplication) {
- // 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.
- }
-
- func applicationWillEnterForeground(application: UIApplication) {
- // 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.
- }
-
- func applicationDidBecomeActive(application: UIApplication) {
- // 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.
- }
-
- func applicationWillTerminate(application: UIApplication) {
- // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
- }
-
-
-}
-
diff --git a/Base.lproj/LaunchScreen.xib b/Base.lproj/LaunchScreen.xib
deleted file mode 100644
index b5956a6..0000000
--- a/Base.lproj/LaunchScreen.xib
+++ /dev/null
@@ -1,41 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/Base.lproj/Main.storyboard b/Base.lproj/Main.storyboard
deleted file mode 100644
index a9409b3..0000000
--- a/Base.lproj/Main.storyboard
+++ /dev/null
@@ -1,615 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/Dindr b/Dindr
new file mode 160000
index 0000000..9aac091
--- /dev/null
+++ b/Dindr
@@ -0,0 +1 @@
+Subproject commit 9aac09113620ec7747b035d6449ef0c77820a046
diff --git a/Dindr-Bridging-Header.h b/Dindr-Bridging-Header.h
deleted file mode 100644
index 69a90ae..0000000
--- a/Dindr-Bridging-Header.h
+++ /dev/null
@@ -1,5 +0,0 @@
-//
-// Use this file to import your target's public headers that you would like to expose to Swift.
-//
-
-#import
\ No newline at end of file
diff --git a/Dindr.xcodeproj/project.pbxproj b/Dindr.xcodeproj/project.pbxproj
new file mode 100644
index 0000000..0e3780c
--- /dev/null
+++ b/Dindr.xcodeproj/project.pbxproj
@@ -0,0 +1,726 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 46;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ A220C6DAAB6AF6BECEAE4045 /* Pods.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B9EF77CB6F97A26FE14C38AE /* Pods.framework */; };
+ CE2D49C11BE06D28007DCBE3 /* SpecialsTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE2D49C01BE06D28007DCBE3 /* SpecialsTableViewCell.swift */; };
+ CE4605481BC33AB1007A2B7D /* GalleryVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE4605471BC33AB1007A2B7D /* GalleryVC.swift */; };
+ CE46054A1BC33FA7007A2B7D /* GalleryCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE4605491BC33FA7007A2B7D /* GalleryCell.swift */; };
+ CE9C42FD1BC1D6CD00504B69 /* AnimationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE9C42F21BC1D6CD00504B69 /* AnimationController.swift */; };
+ CE9C42FE1BC1D6CD00504B69 /* ImageAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE9C42F31BC1D6CD00504B69 /* ImageAction.swift */; };
+ CE9C42FF1BC1D6CD00504B69 /* ImageCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE9C42F41BC1D6CD00504B69 /* ImageCollectionViewCell.swift */; };
+ CE9C43001BC1D6CD00504B69 /* ImagePickerCollectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE9C42F51BC1D6CD00504B69 /* ImagePickerCollectionView.swift */; };
+ CE9C43011BC1D6CD00504B69 /* ImagePickerSheetController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE9C42F71BC1D6CD00504B69 /* ImagePickerSheetController.swift */; };
+ CE9C43021BC1D6CD00504B69 /* ImagePreviewFlowLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE9C42F81BC1D6CD00504B69 /* ImagePreviewFlowLayout.swift */; };
+ CE9C43031BC1D6CD00504B69 /* ImagePreviewTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE9C42F91BC1D6CD00504B69 /* ImagePreviewTableViewCell.swift */; };
+ CE9C43041BC1D6CD00504B69 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = CE9C42FA1BC1D6CD00504B69 /* Images.xcassets */; };
+ CE9C43051BC1D6CD00504B69 /* Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = CE9C42FB1BC1D6CD00504B69 /* Info.plist */; };
+ CE9C43061BC1D6CD00504B69 /* PreviewSupplementaryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE9C42FC1BC1D6CD00504B69 /* PreviewSupplementaryView.swift */; };
+ CE9F9EEF1B802C1B0060D993 /* RestaurantDataViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE9F9EEE1B802C1B0060D993 /* RestaurantDataViewController.swift */; };
+ CEB40EBE1BD6B9D500863F60 /* HomeViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = CEB40EBD1BD6B9D500863F60 /* HomeViewController.m */; };
+ CEB40EC11BD6B9EF00863F60 /* ImageViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = CEB40EC01BD6B9EF00863F60 /* ImageViewController.m */; };
+ CEB40EC41BD6B9FB00863F60 /* VideoViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = CEB40EC31BD6B9FB00863F60 /* VideoViewController.m */; };
+ CEB40EC81BD6BA3C00863F60 /* ViewUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = CEB40EC71BD6BA3C00863F60 /* ViewUtils.m */; };
+ CEB40ECB1BD6BA5D00863F60 /* UIImage+Crop.m in Sources */ = {isa = PBXBuildFile; fileRef = CEB40ECA1BD6BA5D00863F60 /* UIImage+Crop.m */; };
+ CEB40ECE1BD6BA6600863F60 /* UIImage+Resize.m in Sources */ = {isa = PBXBuildFile; fileRef = CEB40ECD1BD6BA6600863F60 /* UIImage+Resize.m */; };
+ CEB40ED21BD6BA9200863F60 /* UIImage+FixOrientation.m in Sources */ = {isa = PBXBuildFile; fileRef = CEB40ED11BD6BA9200863F60 /* UIImage+FixOrientation.m */; };
+ CEB40ED51BD6BA9C00863F60 /* LLSimpleCamera.m in Sources */ = {isa = PBXBuildFile; fileRef = CEB40ED41BD6BA9C00863F60 /* LLSimpleCamera.m */; };
+ CEB40ED81BD6BCE700863F60 /* PreviewImageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEB40ED71BD6BCE700863F60 /* PreviewImageViewController.swift */; };
+ CEB8897A1B7858A000B28A90 /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CEB889791B7858A000B28A90 /* AudioToolbox.framework */; };
+ CEB8897C1B7858A500B28A90 /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CEB8897B1B7858A500B28A90 /* CFNetwork.framework */; };
+ CEB8897E1B7858B300B28A90 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CEB8897D1B7858B300B28A90 /* CoreGraphics.framework */; };
+ CEB889801B7858BA00B28A90 /* CoreLocation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CEB8897F1B7858BA00B28A90 /* CoreLocation.framework */; };
+ CEB889821B7858CD00B28A90 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = CEB889811B7858CD00B28A90 /* libz.dylib */; };
+ CEB889841B7858E500B28A90 /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CEB889831B7858E500B28A90 /* MobileCoreServices.framework */; };
+ CEB889861B7858ED00B28A90 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CEB889851B7858ED00B28A90 /* QuartzCore.framework */; };
+ CEB889881B7858FA00B28A90 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CEB889871B7858FA00B28A90 /* Security.framework */; };
+ CEB8898A1B78590100B28A90 /* StoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CEB889891B78590100B28A90 /* StoreKit.framework */; };
+ CEB8898C1B78591100B28A90 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CEB8898B1B78591100B28A90 /* SystemConfiguration.framework */; };
+ CEB8898E1B78592A00B28A90 /* libsqlite3.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = CEB8898D1B78592A00B28A90 /* libsqlite3.dylib */; };
+ CEBA3B521B7FB261009AE917 /* LoginVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEBA3B511B7FB261009AE917 /* LoginVC.swift */; };
+ CEC9F20D1B7851B3000A74A9 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEC9F20C1B7851B3000A74A9 /* AppDelegate.swift */; };
+ CEC9F2121B7851B3000A74A9 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = CEC9F2101B7851B3000A74A9 /* Main.storyboard */; };
+ CEC9F2141B7851B3000A74A9 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = CEC9F2131B7851B3000A74A9 /* Images.xcassets */; };
+ CEC9F2171B7851B3000A74A9 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = CEC9F2151B7851B3000A74A9 /* LaunchScreen.xib */; };
+ CEC9F2231B7851B3000A74A9 /* DindrTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEC9F2221B7851B3000A74A9 /* DindrTests.swift */; };
+ CEEF5DA01BA8A7610077769E /* RestCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEEF5D9F1BA8A7610077769E /* RestCollectionViewCell.swift */; };
+ CEEF5DA21BA8A8BF0077769E /* DishModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEEF5DA11BA8A8BF0077769E /* DishModel.swift */; };
+ CEEF5DA41BA8B55F0077769E /* SpecialsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEEF5DA31BA8B55F0077769E /* SpecialsTableViewController.swift */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+ CEC9F21D1B7851B3000A74A9 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = CEC9F1FF1B7851B3000A74A9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = CEC9F2061B7851B3000A74A9;
+ remoteInfo = Dindr;
+ };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXFileReference section */
+ A06A68F49A5B1C70F5C4D28D /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.release.xcconfig; path = "Pods/Target Support Files/Pods/Pods.release.xcconfig"; sourceTree = ""; };
+ A16574C15E406AC410350BB4 /* Pods.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.debug.xcconfig; path = "Pods/Target Support Files/Pods/Pods.debug.xcconfig"; sourceTree = ""; };
+ B9EF77CB6F97A26FE14C38AE /* Pods.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ CE2D49C01BE06D28007DCBE3 /* SpecialsTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SpecialsTableViewCell.swift; sourceTree = ""; };
+ CE4605471BC33AB1007A2B7D /* GalleryVC.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GalleryVC.swift; sourceTree = ""; };
+ CE4605491BC33FA7007A2B7D /* GalleryCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GalleryCell.swift; sourceTree = ""; };
+ CE9C42F21BC1D6CD00504B69 /* AnimationController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnimationController.swift; sourceTree = ""; };
+ CE9C42F31BC1D6CD00504B69 /* ImageAction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageAction.swift; sourceTree = ""; };
+ CE9C42F41BC1D6CD00504B69 /* ImageCollectionViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageCollectionViewCell.swift; sourceTree = ""; };
+ CE9C42F51BC1D6CD00504B69 /* ImagePickerCollectionView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImagePickerCollectionView.swift; sourceTree = ""; };
+ CE9C42F61BC1D6CD00504B69 /* ImagePickerSheetController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ImagePickerSheetController.h; sourceTree = ""; };
+ CE9C42F71BC1D6CD00504B69 /* ImagePickerSheetController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImagePickerSheetController.swift; sourceTree = ""; };
+ CE9C42F81BC1D6CD00504B69 /* ImagePreviewFlowLayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImagePreviewFlowLayout.swift; sourceTree = ""; };
+ CE9C42F91BC1D6CD00504B69 /* ImagePreviewTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImagePreviewTableViewCell.swift; sourceTree = ""; };
+ CE9C42FA1BC1D6CD00504B69 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; };
+ CE9C42FB1BC1D6CD00504B69 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+ CE9C42FC1BC1D6CD00504B69 /* PreviewSupplementaryView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PreviewSupplementaryView.swift; sourceTree = ""; };
+ CE9F9EEE1B802C1B0060D993 /* RestaurantDataViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RestaurantDataViewController.swift; sourceTree = ""; };
+ CEB40EBC1BD6B9D500863F60 /* HomeViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HomeViewController.h; sourceTree = ""; };
+ CEB40EBD1BD6B9D500863F60 /* HomeViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HomeViewController.m; sourceTree = ""; };
+ CEB40EBF1BD6B9EF00863F60 /* ImageViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ImageViewController.h; sourceTree = ""; };
+ CEB40EC01BD6B9EF00863F60 /* ImageViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ImageViewController.m; sourceTree = ""; };
+ CEB40EC21BD6B9FB00863F60 /* VideoViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VideoViewController.h; sourceTree = ""; };
+ CEB40EC31BD6B9FB00863F60 /* VideoViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VideoViewController.m; sourceTree = ""; };
+ CEB40EC61BD6BA3C00863F60 /* ViewUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ViewUtils.h; sourceTree = ""; };
+ CEB40EC71BD6BA3C00863F60 /* ViewUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ViewUtils.m; sourceTree = ""; };
+ CEB40EC91BD6BA5D00863F60 /* UIImage+Crop.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+Crop.h"; sourceTree = ""; };
+ CEB40ECA1BD6BA5D00863F60 /* UIImage+Crop.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+Crop.m"; sourceTree = ""; };
+ CEB40ECC1BD6BA6600863F60 /* UIImage+Resize.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+Resize.h"; sourceTree = ""; };
+ CEB40ECD1BD6BA6600863F60 /* UIImage+Resize.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+Resize.m"; sourceTree = ""; };
+ CEB40ED01BD6BA9200863F60 /* UIImage+FixOrientation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+FixOrientation.h"; sourceTree = ""; };
+ CEB40ED11BD6BA9200863F60 /* UIImage+FixOrientation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+FixOrientation.m"; sourceTree = ""; };
+ CEB40ED31BD6BA9C00863F60 /* LLSimpleCamera.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LLSimpleCamera.h; sourceTree = ""; };
+ CEB40ED41BD6BA9C00863F60 /* LLSimpleCamera.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LLSimpleCamera.m; sourceTree = ""; };
+ CEB40ED71BD6BCE700863F60 /* PreviewImageViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PreviewImageViewController.swift; sourceTree = ""; };
+ CEB889791B7858A000B28A90 /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; };
+ CEB8897B1B7858A500B28A90 /* CFNetwork.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CFNetwork.framework; path = System/Library/Frameworks/CFNetwork.framework; sourceTree = SDKROOT; };
+ CEB8897D1B7858B300B28A90 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
+ CEB8897F1B7858BA00B28A90 /* CoreLocation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreLocation.framework; path = System/Library/Frameworks/CoreLocation.framework; sourceTree = SDKROOT; };
+ CEB889811B7858CD00B28A90 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; };
+ CEB889831B7858E500B28A90 /* MobileCoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MobileCoreServices.framework; path = System/Library/Frameworks/MobileCoreServices.framework; sourceTree = SDKROOT; };
+ CEB889851B7858ED00B28A90 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };
+ CEB889871B7858FA00B28A90 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; };
+ CEB889891B78590100B28A90 /* StoreKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = StoreKit.framework; path = System/Library/Frameworks/StoreKit.framework; sourceTree = SDKROOT; };
+ CEB8898B1B78591100B28A90 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; };
+ CEB8898D1B78592A00B28A90 /* libsqlite3.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libsqlite3.dylib; path = usr/lib/libsqlite3.dylib; sourceTree = SDKROOT; };
+ CEB8898F1B78598100B28A90 /* Dindr-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Dindr-Bridging-Header.h"; sourceTree = ""; };
+ CEBA3B511B7FB261009AE917 /* LoginVC.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoginVC.swift; sourceTree = ""; };
+ CEC9F2071B7851B3000A74A9 /* Dindr.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Dindr.app; sourceTree = BUILT_PRODUCTS_DIR; };
+ CEC9F20B1B7851B3000A74A9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+ CEC9F20C1B7851B3000A74A9 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
+ CEC9F2111B7851B3000A74A9 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
+ CEC9F2131B7851B3000A74A9 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; };
+ CEC9F2161B7851B3000A74A9 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; };
+ CEC9F21C1B7851B3000A74A9 /* DindrTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = DindrTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
+ CEC9F2211B7851B3000A74A9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+ CEC9F2221B7851B3000A74A9 /* DindrTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DindrTests.swift; sourceTree = ""; };
+ CEEF5D9F1BA8A7610077769E /* RestCollectionViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RestCollectionViewCell.swift; sourceTree = ""; };
+ CEEF5DA11BA8A8BF0077769E /* DishModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DishModel.swift; sourceTree = ""; };
+ CEEF5DA31BA8B55F0077769E /* SpecialsTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SpecialsTableViewController.swift; sourceTree = ""; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ CEC9F2041B7851B3000A74A9 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ CEB8898E1B78592A00B28A90 /* libsqlite3.dylib in Frameworks */,
+ CEB8898C1B78591100B28A90 /* SystemConfiguration.framework in Frameworks */,
+ CEB8898A1B78590100B28A90 /* StoreKit.framework in Frameworks */,
+ CEB889881B7858FA00B28A90 /* Security.framework in Frameworks */,
+ CEB889861B7858ED00B28A90 /* QuartzCore.framework in Frameworks */,
+ CEB889841B7858E500B28A90 /* MobileCoreServices.framework in Frameworks */,
+ CEB889821B7858CD00B28A90 /* libz.dylib in Frameworks */,
+ CEB889801B7858BA00B28A90 /* CoreLocation.framework in Frameworks */,
+ CEB8897E1B7858B300B28A90 /* CoreGraphics.framework in Frameworks */,
+ CEB8897C1B7858A500B28A90 /* CFNetwork.framework in Frameworks */,
+ CEB8897A1B7858A000B28A90 /* AudioToolbox.framework in Frameworks */,
+ A220C6DAAB6AF6BECEAE4045 /* Pods.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ CEC9F2191B7851B3000A74A9 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 13F1B618C4156F8E977A6AF0 /* Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ CEB8898D1B78592A00B28A90 /* libsqlite3.dylib */,
+ CEB8898B1B78591100B28A90 /* SystemConfiguration.framework */,
+ CEB889891B78590100B28A90 /* StoreKit.framework */,
+ CEB889871B7858FA00B28A90 /* Security.framework */,
+ CEB889851B7858ED00B28A90 /* QuartzCore.framework */,
+ CEB889831B7858E500B28A90 /* MobileCoreServices.framework */,
+ CEB889811B7858CD00B28A90 /* libz.dylib */,
+ CEB8897F1B7858BA00B28A90 /* CoreLocation.framework */,
+ CEB8897D1B7858B300B28A90 /* CoreGraphics.framework */,
+ CEB8897B1B7858A500B28A90 /* CFNetwork.framework */,
+ CEB889791B7858A000B28A90 /* AudioToolbox.framework */,
+ B9EF77CB6F97A26FE14C38AE /* Pods.framework */,
+ );
+ name = Frameworks;
+ sourceTree = "";
+ };
+ CE46054B1BC33FAF007A2B7D /* Gallery */ = {
+ isa = PBXGroup;
+ children = (
+ CE4605471BC33AB1007A2B7D /* GalleryVC.swift */,
+ CE4605491BC33FA7007A2B7D /* GalleryCell.swift */,
+ );
+ name = Gallery;
+ sourceTree = "";
+ };
+ CE9C42F01BC1D36000504B69 /* Login */ = {
+ isa = PBXGroup;
+ children = (
+ CEBA3B511B7FB261009AE917 /* LoginVC.swift */,
+ );
+ name = Login;
+ sourceTree = "";
+ };
+ CE9C42F11BC1D6CD00504B69 /* ImagePickerSheet6.4 */ = {
+ isa = PBXGroup;
+ children = (
+ CE9C42F21BC1D6CD00504B69 /* AnimationController.swift */,
+ CE9C42F31BC1D6CD00504B69 /* ImageAction.swift */,
+ CE9C42F41BC1D6CD00504B69 /* ImageCollectionViewCell.swift */,
+ CE9C42F51BC1D6CD00504B69 /* ImagePickerCollectionView.swift */,
+ CE9C42F61BC1D6CD00504B69 /* ImagePickerSheetController.h */,
+ CE9C42F71BC1D6CD00504B69 /* ImagePickerSheetController.swift */,
+ CE9C42F81BC1D6CD00504B69 /* ImagePreviewFlowLayout.swift */,
+ CE9C42F91BC1D6CD00504B69 /* ImagePreviewTableViewCell.swift */,
+ CE9C42FA1BC1D6CD00504B69 /* Images.xcassets */,
+ CE9C42FB1BC1D6CD00504B69 /* Info.plist */,
+ CE9C42FC1BC1D6CD00504B69 /* PreviewSupplementaryView.swift */,
+ );
+ path = ImagePickerSheet6.4;
+ sourceTree = "";
+ };
+ CEB40EC51BD6BA1100863F60 /* CameraControllers */ = {
+ isa = PBXGroup;
+ children = (
+ CEB40EBC1BD6B9D500863F60 /* HomeViewController.h */,
+ CEB40EBD1BD6B9D500863F60 /* HomeViewController.m */,
+ CEB40EBF1BD6B9EF00863F60 /* ImageViewController.h */,
+ CEB40EC01BD6B9EF00863F60 /* ImageViewController.m */,
+ CEB40EC21BD6B9FB00863F60 /* VideoViewController.h */,
+ CEB40EC31BD6B9FB00863F60 /* VideoViewController.m */,
+ );
+ name = CameraControllers;
+ sourceTree = "";
+ };
+ CEB40ECF1BD6BA7300863F60 /* CameraUtilities */ = {
+ isa = PBXGroup;
+ children = (
+ CEB40EC91BD6BA5D00863F60 /* UIImage+Crop.h */,
+ CEB40ECA1BD6BA5D00863F60 /* UIImage+Crop.m */,
+ CEB40EC61BD6BA3C00863F60 /* ViewUtils.h */,
+ CEB40EC71BD6BA3C00863F60 /* ViewUtils.m */,
+ CEB40ECC1BD6BA6600863F60 /* UIImage+Resize.h */,
+ CEB40ECD1BD6BA6600863F60 /* UIImage+Resize.m */,
+ );
+ name = CameraUtilities;
+ sourceTree = "";
+ };
+ CEB40ED61BD6BAA700863F60 /* LLSimpleCamera */ = {
+ isa = PBXGroup;
+ children = (
+ CEB40ED01BD6BA9200863F60 /* UIImage+FixOrientation.h */,
+ CEB40ED11BD6BA9200863F60 /* UIImage+FixOrientation.m */,
+ CEB40ED31BD6BA9C00863F60 /* LLSimpleCamera.h */,
+ CEB40ED41BD6BA9C00863F60 /* LLSimpleCamera.m */,
+ );
+ name = LLSimpleCamera;
+ sourceTree = "";
+ };
+ CEC9F1FE1B7851B3000A74A9 = {
+ isa = PBXGroup;
+ children = (
+ CEC9F2091B7851B3000A74A9 /* Dindr */,
+ CEC9F21F1B7851B3000A74A9 /* DindrTests */,
+ CE9C42F11BC1D6CD00504B69 /* ImagePickerSheet6.4 */,
+ CEC9F2081B7851B3000A74A9 /* Products */,
+ DDA2E1AC0F8591B8D089FC9A /* Pods */,
+ 13F1B618C4156F8E977A6AF0 /* Frameworks */,
+ );
+ sourceTree = "";
+ };
+ CEC9F2081B7851B3000A74A9 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ CEC9F2071B7851B3000A74A9 /* Dindr.app */,
+ CEC9F21C1B7851B3000A74A9 /* DindrTests.xctest */,
+ );
+ name = Products;
+ sourceTree = "";
+ };
+ CEC9F2091B7851B3000A74A9 /* Dindr */ = {
+ isa = PBXGroup;
+ children = (
+ CEB40EC51BD6BA1100863F60 /* CameraControllers */,
+ CEB40ECF1BD6BA7300863F60 /* CameraUtilities */,
+ CEB40ED61BD6BAA700863F60 /* LLSimpleCamera */,
+ CEC9F20C1B7851B3000A74A9 /* AppDelegate.swift */,
+ CE9C42F01BC1D36000504B69 /* Login */,
+ CE9F9EEE1B802C1B0060D993 /* RestaurantDataViewController.swift */,
+ CEEF5D9F1BA8A7610077769E /* RestCollectionViewCell.swift */,
+ CEEF5DA31BA8B55F0077769E /* SpecialsTableViewController.swift */,
+ CE2D49C01BE06D28007DCBE3 /* SpecialsTableViewCell.swift */,
+ CE46054B1BC33FAF007A2B7D /* Gallery */,
+ CEEF5DA11BA8A8BF0077769E /* DishModel.swift */,
+ CEB40ED71BD6BCE700863F60 /* PreviewImageViewController.swift */,
+ CEC9F2101B7851B3000A74A9 /* Main.storyboard */,
+ CEC9F2131B7851B3000A74A9 /* Images.xcassets */,
+ CEC9F2151B7851B3000A74A9 /* LaunchScreen.xib */,
+ CEC9F20A1B7851B3000A74A9 /* Supporting Files */,
+ CEB8898F1B78598100B28A90 /* Dindr-Bridging-Header.h */,
+ );
+ path = Dindr;
+ sourceTree = "";
+ };
+ CEC9F20A1B7851B3000A74A9 /* Supporting Files */ = {
+ isa = PBXGroup;
+ children = (
+ CEC9F20B1B7851B3000A74A9 /* Info.plist */,
+ );
+ name = "Supporting Files";
+ sourceTree = "";
+ };
+ CEC9F21F1B7851B3000A74A9 /* DindrTests */ = {
+ isa = PBXGroup;
+ children = (
+ CEC9F2221B7851B3000A74A9 /* DindrTests.swift */,
+ CEC9F2201B7851B3000A74A9 /* Supporting Files */,
+ );
+ path = DindrTests;
+ sourceTree = "";
+ };
+ CEC9F2201B7851B3000A74A9 /* Supporting Files */ = {
+ isa = PBXGroup;
+ children = (
+ CEC9F2211B7851B3000A74A9 /* Info.plist */,
+ );
+ name = "Supporting Files";
+ sourceTree = "";
+ };
+ DDA2E1AC0F8591B8D089FC9A /* Pods */ = {
+ isa = PBXGroup;
+ children = (
+ A16574C15E406AC410350BB4 /* Pods.debug.xcconfig */,
+ A06A68F49A5B1C70F5C4D28D /* Pods.release.xcconfig */,
+ );
+ name = Pods;
+ sourceTree = "";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ CEC9F2061B7851B3000A74A9 /* Dindr */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = CEC9F2261B7851B3000A74A9 /* Build configuration list for PBXNativeTarget "Dindr" */;
+ buildPhases = (
+ 94CC3B6E7308AC77FEB8A40C /* Check Pods Manifest.lock */,
+ CEC9F2031B7851B3000A74A9 /* Sources */,
+ CEC9F2041B7851B3000A74A9 /* Frameworks */,
+ CEC9F2051B7851B3000A74A9 /* Resources */,
+ 93EB0F68B7448BEF1603AA07 /* Copy Pods Resources */,
+ 5C8D724AC76E44C64B9AE57E /* Embed Pods Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = Dindr;
+ productName = Dindr;
+ productReference = CEC9F2071B7851B3000A74A9 /* Dindr.app */;
+ productType = "com.apple.product-type.application";
+ };
+ CEC9F21B1B7851B3000A74A9 /* DindrTests */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = CEC9F2291B7851B3000A74A9 /* Build configuration list for PBXNativeTarget "DindrTests" */;
+ buildPhases = (
+ CEC9F2181B7851B3000A74A9 /* Sources */,
+ CEC9F2191B7851B3000A74A9 /* Frameworks */,
+ CEC9F21A1B7851B3000A74A9 /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ CEC9F21E1B7851B3000A74A9 /* PBXTargetDependency */,
+ );
+ name = DindrTests;
+ productName = DindrTests;
+ productReference = CEC9F21C1B7851B3000A74A9 /* DindrTests.xctest */;
+ productType = "com.apple.product-type.bundle.unit-test";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ CEC9F1FF1B7851B3000A74A9 /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ LastSwiftMigration = 0710;
+ LastSwiftUpdateCheck = 0710;
+ LastUpgradeCheck = 0640;
+ ORGANIZATIONNAME = ImagineME;
+ TargetAttributes = {
+ CEC9F2061B7851B3000A74A9 = {
+ CreatedOnToolsVersion = 6.4;
+ };
+ CEC9F21B1B7851B3000A74A9 = {
+ CreatedOnToolsVersion = 6.4;
+ TestTargetID = CEC9F2061B7851B3000A74A9;
+ };
+ };
+ };
+ buildConfigurationList = CEC9F2021B7851B3000A74A9 /* Build configuration list for PBXProject "Dindr" */;
+ compatibilityVersion = "Xcode 3.2";
+ developmentRegion = English;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ Base,
+ );
+ mainGroup = CEC9F1FE1B7851B3000A74A9;
+ productRefGroup = CEC9F2081B7851B3000A74A9 /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ CEC9F2061B7851B3000A74A9 /* Dindr */,
+ CEC9F21B1B7851B3000A74A9 /* DindrTests */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ CEC9F2051B7851B3000A74A9 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ CEC9F2121B7851B3000A74A9 /* Main.storyboard in Resources */,
+ CEC9F2171B7851B3000A74A9 /* LaunchScreen.xib in Resources */,
+ CE9C43041BC1D6CD00504B69 /* Images.xcassets in Resources */,
+ CEC9F2141B7851B3000A74A9 /* Images.xcassets in Resources */,
+ CE9C43051BC1D6CD00504B69 /* Info.plist in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ CEC9F21A1B7851B3000A74A9 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXShellScriptBuildPhase section */
+ 5C8D724AC76E44C64B9AE57E /* Embed Pods Frameworks */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "Embed Pods Frameworks";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-frameworks.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
+ 93EB0F68B7448BEF1603AA07 /* 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;
+ };
+ 94CC3B6E7308AC77FEB8A40C /* 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 */
+ CEC9F2031B7851B3000A74A9 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ CE9C43031BC1D6CD00504B69 /* ImagePreviewTableViewCell.swift in Sources */,
+ CEEF5DA21BA8A8BF0077769E /* DishModel.swift in Sources */,
+ CEB40EC81BD6BA3C00863F60 /* ViewUtils.m in Sources */,
+ CEB40ED51BD6BA9C00863F60 /* LLSimpleCamera.m in Sources */,
+ CE9C43011BC1D6CD00504B69 /* ImagePickerSheetController.swift in Sources */,
+ CEB40ECB1BD6BA5D00863F60 /* UIImage+Crop.m in Sources */,
+ CE9C42FF1BC1D6CD00504B69 /* ImageCollectionViewCell.swift in Sources */,
+ CE46054A1BC33FA7007A2B7D /* GalleryCell.swift in Sources */,
+ CE2D49C11BE06D28007DCBE3 /* SpecialsTableViewCell.swift in Sources */,
+ CE9C43061BC1D6CD00504B69 /* PreviewSupplementaryView.swift in Sources */,
+ CE9C43021BC1D6CD00504B69 /* ImagePreviewFlowLayout.swift in Sources */,
+ CE9C42FE1BC1D6CD00504B69 /* ImageAction.swift in Sources */,
+ CEB40EC11BD6B9EF00863F60 /* ImageViewController.m in Sources */,
+ CE9F9EEF1B802C1B0060D993 /* RestaurantDataViewController.swift in Sources */,
+ CEC9F20D1B7851B3000A74A9 /* AppDelegate.swift in Sources */,
+ CE4605481BC33AB1007A2B7D /* GalleryVC.swift in Sources */,
+ CEEF5DA41BA8B55F0077769E /* SpecialsTableViewController.swift in Sources */,
+ CEEF5DA01BA8A7610077769E /* RestCollectionViewCell.swift in Sources */,
+ CE9C42FD1BC1D6CD00504B69 /* AnimationController.swift in Sources */,
+ CEBA3B521B7FB261009AE917 /* LoginVC.swift in Sources */,
+ CEB40ED81BD6BCE700863F60 /* PreviewImageViewController.swift in Sources */,
+ CEB40ECE1BD6BA6600863F60 /* UIImage+Resize.m in Sources */,
+ CEB40EC41BD6B9FB00863F60 /* VideoViewController.m in Sources */,
+ CEB40EBE1BD6B9D500863F60 /* HomeViewController.m in Sources */,
+ CEB40ED21BD6BA9200863F60 /* UIImage+FixOrientation.m in Sources */,
+ CE9C43001BC1D6CD00504B69 /* ImagePickerCollectionView.swift in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ CEC9F2181B7851B3000A74A9 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ CEC9F2231B7851B3000A74A9 /* DindrTests.swift in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+ CEC9F21E1B7851B3000A74A9 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = CEC9F2061B7851B3000A74A9 /* Dindr */;
+ targetProxy = CEC9F21D1B7851B3000A74A9 /* PBXContainerItemProxy */;
+ };
+/* End PBXTargetDependency section */
+
+/* Begin PBXVariantGroup section */
+ CEC9F2101B7851B3000A74A9 /* Main.storyboard */ = {
+ isa = PBXVariantGroup;
+ children = (
+ CEC9F2111B7851B3000A74A9 /* Base */,
+ );
+ name = Main.storyboard;
+ sourceTree = "";
+ };
+ CEC9F2151B7851B3000A74A9 /* LaunchScreen.xib */ = {
+ isa = PBXVariantGroup;
+ children = (
+ CEC9F2161B7851B3000A74A9 /* Base */,
+ );
+ name = LaunchScreen.xib;
+ sourceTree = "";
+ };
+/* End PBXVariantGroup section */
+
+/* Begin XCBuildConfiguration section */
+ CEC9F2241B7851B3000A74A9 /* 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-with-dsym";
+ ENABLE_STRICT_OBJC_MSGSEND = 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_SYMBOLS_PRIVATE_EXTERN = NO;
+ 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 = 8.4;
+ MTL_ENABLE_DEBUG_INFO = YES;
+ ONLY_ACTIVE_ARCH = YES;
+ SDKROOT = iphoneos;
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ };
+ name = Debug;
+ };
+ CEC9F2251B7851B3000A74A9 /* 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 = 8.4;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ SDKROOT = iphoneos;
+ VALIDATE_PRODUCT = YES;
+ };
+ name = Release;
+ };
+ CEC9F2271B7851B3000A74A9 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = A16574C15E406AC410350BB4 /* Pods.debug.xcconfig */;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CLANG_ENABLE_MODULES = YES;
+ INFOPLIST_FILE = Dindr/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_OBJC_BRIDGING_HEADER = "Dindr/Dindr-Bridging-Header.h";
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ };
+ name = Debug;
+ };
+ CEC9F2281B7851B3000A74A9 /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = A06A68F49A5B1C70F5C4D28D /* Pods.release.xcconfig */;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CLANG_ENABLE_MODULES = YES;
+ INFOPLIST_FILE = Dindr/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_OBJC_BRIDGING_HEADER = "Dindr/Dindr-Bridging-Header.h";
+ };
+ name = Release;
+ };
+ CEC9F22A1B7851B3000A74A9 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ BUNDLE_LOADER = "$(TEST_HOST)";
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(SDKROOT)/Developer/Library/Frameworks",
+ "$(inherited)",
+ );
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ INFOPLIST_FILE = DindrTests/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Dindr.app/Dindr";
+ };
+ name = Debug;
+ };
+ CEC9F22B1B7851B3000A74A9 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ BUNDLE_LOADER = "$(TEST_HOST)";
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(SDKROOT)/Developer/Library/Frameworks",
+ "$(inherited)",
+ );
+ INFOPLIST_FILE = DindrTests/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Dindr.app/Dindr";
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ CEC9F2021B7851B3000A74A9 /* Build configuration list for PBXProject "Dindr" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ CEC9F2241B7851B3000A74A9 /* Debug */,
+ CEC9F2251B7851B3000A74A9 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ CEC9F2261B7851B3000A74A9 /* Build configuration list for PBXNativeTarget "Dindr" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ CEC9F2271B7851B3000A74A9 /* Debug */,
+ CEC9F2281B7851B3000A74A9 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ CEC9F2291B7851B3000A74A9 /* Build configuration list for PBXNativeTarget "DindrTests" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ CEC9F22A1B7851B3000A74A9 /* Debug */,
+ CEC9F22B1B7851B3000A74A9 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = CEC9F1FF1B7851B3000A74A9 /* Project object */;
+}
diff --git a/Dindr.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Dindr.xcodeproj/project.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000..8f43cb9
--- /dev/null
+++ b/Dindr.xcodeproj/project.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+
+
+
+
+
diff --git a/Dindr.xcworkspace/contents.xcworkspacedata b/Dindr.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000..d00d341
--- /dev/null
+++ b/Dindr.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
diff --git a/Dindr.xcworkspace/xcshareddata/Dindr.xcscmblueprint b/Dindr.xcworkspace/xcshareddata/Dindr.xcscmblueprint
new file mode 100644
index 0000000..a4f5da2
--- /dev/null
+++ b/Dindr.xcworkspace/xcshareddata/Dindr.xcscmblueprint
@@ -0,0 +1,30 @@
+{
+ "DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey" : "EACED2723BB5600B88834009D10CCB8CD2946702",
+ "DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey" : {
+
+ },
+ "DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey" : {
+ "EACED2723BB5600B88834009D10CCB8CD2946702" : 0,
+ "3CE173A00AFA646F21499F4BA53E756FEAEB54D6" : 0
+ },
+ "DVTSourceControlWorkspaceBlueprintIdentifierKey" : "637F2BFC-C9BA-434D-A08A-479B2E1C1C63",
+ "DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : {
+ "EACED2723BB5600B88834009D10CCB8CD2946702" : "Dindr\/",
+ "3CE173A00AFA646F21499F4BA53E756FEAEB54D6" : "Dindr\/Dindr\/"
+ },
+ "DVTSourceControlWorkspaceBlueprintNameKey" : "Dindr",
+ "DVTSourceControlWorkspaceBlueprintVersion" : 204,
+ "DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "Dindr.xcworkspace",
+ "DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [
+ {
+ "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/lsecrease\/Dindr.git",
+ "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
+ "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "3CE173A00AFA646F21499F4BA53E756FEAEB54D6"
+ },
+ {
+ "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/JBader89\/RestaurantDindr.git",
+ "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
+ "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "EACED2723BB5600B88834009D10CCB8CD2946702"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/DindrTests/DindrTests.swift b/DindrTests/DindrTests.swift
new file mode 100644
index 0000000..b691401
--- /dev/null
+++ b/DindrTests/DindrTests.swift
@@ -0,0 +1,36 @@
+//
+// DindrTests.swift
+// DindrTests
+//
+// Created by lsecrease on 8/9/15.
+// Copyright (c) 2015 ImagineME. All rights reserved.
+//
+
+import UIKit
+import XCTest
+
+class DindrTests: XCTestCase {
+
+ override func setUp() {
+ super.setUp()
+ // Put setup code here. This method is called before the invocation of each test method in the class.
+ }
+
+ override func tearDown() {
+ // Put teardown code here. This method is called after the invocation of each test method in the class.
+ super.tearDown()
+ }
+
+ func testExample() {
+ // This is an example of a functional test case.
+ XCTAssert(true, "Pass")
+ }
+
+ func testPerformanceExample() {
+ // This is an example of a performance test case.
+ self.measureBlock() {
+ // Put the code you want to measure the time of here.
+ }
+ }
+
+}
diff --git a/Info.plist b/DindrTests/Info.plist
similarity index 59%
rename from Info.plist
rename to DindrTests/Info.plist
index 4fba926..c84165a 100644
--- a/Info.plist
+++ b/DindrTests/Info.plist
@@ -13,28 +13,12 @@
CFBundleName$(PRODUCT_NAME)CFBundlePackageType
- APPL
+ BNDLCFBundleShortVersionString1.0CFBundleSignature????CFBundleVersion1
- LSRequiresIPhoneOS
-
- UILaunchStoryboardName
- LaunchScreen
- UIMainStoryboardFile
- Main
- UIRequiredDeviceCapabilities
-
- armv7
-
- UISupportedInterfaceOrientations
-
- UIInterfaceOrientationPortrait
- UIInterfaceOrientationLandscapeLeft
- UIInterfaceOrientationLandscapeRight
-
diff --git a/DishModel.swift b/DishModel.swift
deleted file mode 100644
index 6cd0845..0000000
--- a/DishModel.swift
+++ /dev/null
@@ -1,15 +0,0 @@
-//
-// DishModel.swift
-// Dindr
-//
-// Created by lsecrease on 9/15/15.
-// Copyright (c) 2015 ImagineME. All rights reserved.
-//
-
-import Foundation
-
-struct DishModel {
-
- var image = UIImage(named: "")
-
-}
\ No newline at end of file
diff --git a/GalleryCell.swift b/GalleryCell.swift
deleted file mode 100644
index f73c6c8..0000000
--- a/GalleryCell.swift
+++ /dev/null
@@ -1,14 +0,0 @@
-//
-// GalleryCell.swift
-// Dindr
-//
-// Created by lsecrease on 10/5/15.
-// Copyright (c) 2015 ImagineME. All rights reserved.
-//
-
-import UIKit
-
-class GalleryCell: UICollectionViewCell {
-
- @IBOutlet weak var galImage: UIImageView!
-}
diff --git a/GalleryVC.swift b/GalleryVC.swift
deleted file mode 100644
index 34fc073..0000000
--- a/GalleryVC.swift
+++ /dev/null
@@ -1,177 +0,0 @@
-//
-// GalleryVC.swift
-// Dindr
-//
-// Created by lsecrease on 10/5/15.
-// Copyright (c) 2015 ImagineME. All rights reserved.
-//
-
-import UIKit
-
-
-class GalleryVC: UIViewController, UICollectionViewDataSource,
- UICollectionViewDelegate,
- UICollectionViewDelegateFlowLayout,
-UIScrollViewDelegate {
-
- /* Views */
- @IBOutlet var galleryCollView: UICollectionView!
-
- @IBOutlet var imagePreviewView: UIView!
- @IBOutlet var imgScrollView: UIScrollView!
- @IBOutlet var imgPrev: UIImageView!
-
-
- /* Variables */
- var galleryArray = NSMutableArray()
-
- var collViewCells: CGFloat = 3.0
-
- var hudView = UIView(frame: CGRectMake(0, 0, 80, 80))
- var indicatorView = UIActivityIndicatorView(frame: CGRectMake(0, 0, 80, 80))
-
-
-
-
- override func viewDidLoad() {
- super.viewDidLoad()
-
- imagePreviewView.frame = CGRectMake(0, 0, 0, 0)
-
- queryGallery()
-
- //println("\(galleryArray.count)")
-
-
-
-
- }
-
- func viewForZoomingInScrollView(scrollView: UIScrollView) -> UIView? {
- return imgPrev
- }
-
- func queryGallery() {
-
- // ERROR ALERT VIEW
- var errorAlert = UIAlertView(title: "Dindr",
- message: "Something went wrong, try again later or check your internet connection",
- delegate: nil,
- cancelButtonTitle: "OK" )
-
- view.showHUD(view)
- galleryArray.removeAllObjects()
-
- var query = PFQuery(className: "Gallery")
- query.findObjectsInBackgroundWithBlock { (objects, error)-> Void in
- if error == nil {
- if let objects = objects as? [PFObject] {
- for object in objects {
- self.galleryArray.addObject(object)
- } }
- // Reload Data
- self.galleryCollView.reloadData()
- self.view.hideHUD()
- println("\(self.galleryArray.count)")
-
- } else { errorAlert.show(); self.view.hideHUD() }
- }
- }
-
-
-
- /* MARK: - COLLECTION VIEW DELEGATES ========================*/
- func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
- return 1
- }
-
- func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
- return galleryArray.count
-
- }
-
- func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
- let cell = collectionView.dequeueReusableCellWithReuseIdentifier("GalleryCell", forIndexPath: indexPath) as! GalleryCell
-
- var galleryClass = PFObject(className: "Gallery")
- galleryClass = galleryArray[indexPath.row] as! PFObject
-
-
- // Get image
- let imageFile = galleryClass["image"] as? PFFile
- imageFile?.getDataInBackgroundWithBlock { (imageData: NSData?, error: NSError?) -> Void in
- if error == nil {
- if let imageData = imageData {
- cell.galImage.image = UIImage(data:imageData)
- cell.galImage.layer.borderColor = UIColor.blackColor().CGColor
- cell.galImage.layer.borderWidth = 1
- } } }
-//
-
- return cell
- }
-
- func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
- return CGSizeMake(view.frame.size.width / collViewCells, view.frame.size.width / collViewCells)
- }
-
- // IMAGE TAPPED
- func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
-
- var galleryClass = PFObject(className: "Gallery")
- galleryClass = galleryArray[indexPath.row] as! PFObject
-
- let imageFile = galleryClass["image"] as? PFFile
- imageFile?.getDataInBackgroundWithBlock { (imageData: NSData?, error: NSError?) -> Void in
- if error == nil {
- if let imageData = imageData {
- self.imgPrev.image = UIImage(data:imageData)
- self.showImagePrevView()
- } } }
- }
-
-
-
-
- // SHOW/HIDE PREVIEW IMAGE VIEW
- func showImagePrevView() {
- UIView.animateWithDuration(0.1, delay: 0.0, options: UIViewAnimationOptions.CurveLinear, animations: {
- self.imagePreviewView.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)
- }, completion: { (finished: Bool) in })
- }
- func hideImagePrevView() {
- imgPrev.image = nil
- UIView.animateWithDuration(0.1, delay: 0.0, options: UIViewAnimationOptions.CurveLinear, animations: {
- self.imagePreviewView.frame = CGRectMake(0, 0, 0, 0)
- }, completion: { (finished: Bool) in })
- }
-
-
- // TAP ON IMAGE TO CLOSE PREVIEW
- @IBAction func tapToClosePreview(sender: UITapGestureRecognizer) {
- hideImagePrevView()
- }
-
-
-}
-
-extension UIView {
- func showHUD(inView: UIView) {
- hudView.center = CGPointMake(inView.frame.size.width/2, inView.frame.size.height/2)
- hudView.backgroundColor = UIColor(red: 237.0/255.0, green: 85.0/255.0, blue: 100.0/255.0, alpha: 1.0)
- hudView.alpha = 0.9
- hudView.layer.cornerRadius = hudView.bounds.size.width/2
-
- indicatorView.center = CGPointMake(hudView.frame.size.width/2, hudView.frame.size.height/2)
- indicatorView.activityIndicatorViewStyle = UIActivityIndicatorViewStyle.WhiteLarge
- hudView.addSubview(indicatorView)
- inView.addSubview(hudView)
- indicatorView.startAnimating()
- }
-
- func hideHUD() { hudView.removeFromSuperview() }
-}
-
-
-
-
diff --git a/HomeViewController.h b/HomeViewController.h
deleted file mode 100755
index 9df38b4..0000000
--- a/HomeViewController.h
+++ /dev/null
@@ -1,14 +0,0 @@
-//
-// HomeViewController.h
-// LLSimpleCameraExample
-//
-// Created by Ömer Faruk Gül on 29/10/14.
-// Copyright (c) 2014 Ömer Faruk Gül. All rights reserved.
-//
-
-#import
-#import "LLSimpleCamera.h"
-
-@interface HomeViewController : UIViewController
-
-@end
diff --git a/HomeViewController.m b/HomeViewController.m
deleted file mode 100755
index 8a0ce6d..0000000
--- a/HomeViewController.m
+++ /dev/null
@@ -1,292 +0,0 @@
-//
-// HomeViewController.m
-// LLSimpleCameraExample
-//
-// Created by Ömer Faruk Gül on 29/10/14.
-// Copyright (c) 2014 Ömer Faruk Gül. All rights reserved.
-//
-
-#import "HomeViewController.h"
-#import "ViewUtils.h"
-#import "ImageViewController.h"
-#import "VideoViewController.h"
-#import "Dindr-Swift.h"
-
-
-@interface HomeViewController ()
-@property (strong, nonatomic) LLSimpleCamera *camera;
-@property (strong, nonatomic) UILabel *errorLabel;
-@property (strong, nonatomic) UIButton *snapButton;
-@property (strong, nonatomic) UIButton *switchButton;
-@property (strong, nonatomic) UIButton *flashButton;
-@property (strong, nonatomic) UISegmentedControl *segmentedControl;
-@end
-
-@implementation HomeViewController
-
-- (void)viewDidLoad {
- [super viewDidLoad];
-
- self.view.backgroundColor = [UIColor blackColor];
- [self.navigationController setNavigationBarHidden:YES animated:NO];
-
- CGRect screenRect = [[UIScreen mainScreen] bounds];
-
- // ----- initialize camera -------- //
-
- // create camera vc
- self.camera = [[LLSimpleCamera alloc] initWithQuality:AVCaptureSessionPresetHigh
- position:CameraPositionBack
- videoEnabled:YES];
-
- // attach to a view controller
- [self.camera attachToViewController:self withFrame:CGRectMake(0, 0, screenRect.size.width, screenRect.size.height)];
-
- // read: http://stackoverflow.com/questions/5427656/ios-uiimagepickercontroller-result-image-orientation-after-upload
- // you probably will want to set this to YES, if you are going view the image outside iOS.
- self.camera.fixOrientationAfterCapture = NO;
-
- // take the required actions on a device change
- __weak typeof(self) weakSelf = self;
- [self.camera setOnDeviceChange:^(LLSimpleCamera *camera, AVCaptureDevice * device) {
-
- NSLog(@"Device changed.");
-
- // device changed, check if flash is available
- if([camera isFlashAvailable]) {
- weakSelf.flashButton.hidden = NO;
-
- if(camera.flash == CameraFlashOff) {
- weakSelf.flashButton.selected = NO;
- }
- else {
- weakSelf.flashButton.selected = YES;
- }
- }
- else {
- weakSelf.flashButton.hidden = YES;
- }
- }];
-
- [self.camera setOnError:^(LLSimpleCamera *camera, NSError *error) {
- NSLog(@"Camera error: %@", error);
-
- if([error.domain isEqualToString:LLSimpleCameraErrorDomain]) {
- if(error.code == LLSimpleCameraErrorCodeCameraPermission ||
- error.code == LLSimpleCameraErrorCodeMicrophonePermission) {
-
- if(weakSelf.errorLabel) {
- [weakSelf.errorLabel removeFromSuperview];
- }
-
- UILabel *label = [[UILabel alloc] initWithFrame:CGRectZero];
- label.text = @"We need permission for the camera.\nPlease go to your settings.";
- label.numberOfLines = 2;
- label.lineBreakMode = NSLineBreakByWordWrapping;
- label.backgroundColor = [UIColor clearColor];
- label.font = [UIFont fontWithName:@"AvenirNext-DemiBold" size:13.0f];
- label.textColor = [UIColor whiteColor];
- label.textAlignment = NSTextAlignmentCenter;
- [label sizeToFit];
- label.center = CGPointMake(screenRect.size.width / 2.0f, screenRect.size.height / 2.0f);
- weakSelf.errorLabel = label;
- [weakSelf.view addSubview:weakSelf.errorLabel];
- }
- }
- }];
-
- // ----- camera buttons -------- //
-
- // snap button to capture image
- self.snapButton = [UIButton buttonWithType:UIButtonTypeCustom];
- self.snapButton.frame = CGRectMake(0, 0, 70.0f, 70.0f);
- self.snapButton.clipsToBounds = YES;
- self.snapButton.layer.cornerRadius = self.snapButton.width / 2.0f;
- self.snapButton.layer.borderColor = [UIColor whiteColor].CGColor;
- self.snapButton.layer.borderWidth = 2.0f;
- self.snapButton.backgroundColor = [[UIColor whiteColor] colorWithAlphaComponent:0.5];
- self.snapButton.layer.rasterizationScale = [UIScreen mainScreen].scale;
- self.snapButton.layer.shouldRasterize = YES;
- [self.snapButton addTarget:self action:@selector(snapButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
- [self.view addSubview:self.snapButton];
-
- // button to toggle flash
- self.flashButton = [UIButton buttonWithType:UIButtonTypeSystem];
- self.flashButton.frame = CGRectMake(0, 0, 16.0f + 20.0f, 24.0f + 20.0f);
- self.flashButton.tintColor = [UIColor whiteColor];
- [self.flashButton setImage:[UIImage imageNamed:@"camera-flash.png"] forState:UIControlStateNormal];
- self.flashButton.imageEdgeInsets = UIEdgeInsetsMake(10.0f, 10.0f, 10.0f, 10.0f);
- [self.flashButton addTarget:self action:@selector(flashButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
- [self.view addSubview:self.flashButton];
-
- // button to toggle camera positions
- self.switchButton = [UIButton buttonWithType:UIButtonTypeSystem];
- self.switchButton.frame = CGRectMake(0, 0, 29.0f + 20.0f, 22.0f + 20.0f);
- self.switchButton.tintColor = [UIColor whiteColor];
- [self.switchButton setImage:[UIImage imageNamed:@"camera-switch.png"] forState:UIControlStateNormal];
- self.switchButton.imageEdgeInsets = UIEdgeInsetsMake(10.0f, 10.0f, 10.0f, 10.0f);
- [self.switchButton addTarget:self action:@selector(switchButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
- [self.view addSubview:self.switchButton];
-
-
- self.segmentedControl = [[UISegmentedControl alloc] initWithItems:@[@"Picture",@"Video"]];
- self.segmentedControl.frame = CGRectMake(12.0f, screenRect.size.height - 67.0f, 120.0f, 32.0f);
- self.segmentedControl.selectedSegmentIndex = 0;
- self.segmentedControl.tintColor = [UIColor whiteColor];
- [self.segmentedControl addTarget:self action:@selector(segmentedControlValueChanged:) forControlEvents:UIControlEventValueChanged];
- [self.view addSubview:self.segmentedControl];
-}
-
-- (void)segmentedControlValueChanged:(UISegmentedControl *)control {
- NSLog(@"Segment value changed!");
-}
-
-- (void)viewWillAppear:(BOOL)animated {
- [super viewWillAppear:animated];
-
- // start the camera
- [self.camera start];
-}
-
-- (void)viewWillDisappear:(BOOL)animated {
- [super viewWillDisappear:animated];
-
- // stop the camera
- [self.camera stop];
-}
-
-/* camera button methods */
-
-- (void)switchButtonPressed:(UIButton *)button {
- [self.camera togglePosition];
-}
-
-- (NSURL *)applicationDocumentsDirectory {
- return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory
- inDomains:NSUserDomainMask] lastObject];
-}
-
-- (void)flashButtonPressed:(UIButton *)button {
-
- if(self.camera.flash == CameraFlashOff) {
- BOOL done = [self.camera updateFlashMode:CameraFlashOn];
- if(done) {
- self.flashButton.selected = YES;
- self.flashButton.tintColor = [UIColor yellowColor];
- }
- }
- else {
- BOOL done = [self.camera updateFlashMode:CameraFlashOff];
- if(done) {
- self.flashButton.selected = NO;
- self.flashButton.tintColor = [UIColor whiteColor];
- }
- }
-}
-
-- (void)snapButtonPressed:(UIButton *)button {
-
- if(self.segmentedControl.selectedSegmentIndex == 0) {
- // capture
- [self.camera capture:^(LLSimpleCamera *camera, UIImage *image, NSDictionary *metadata, NSError *error) {
- if(!error) {
-
- // we should stop the camera, since we don't need it anymore. We will open a new vc.
- // this very important, otherwise you may experience memory crashes
- [camera stop];
-
- // show the image
-
- [self performSegueWithIdentifier:@"Show Image Preview" sender:image];
- }
- else {
- NSLog(@"An error has occured: %@", error);
- }
- } exactSeenImage:YES];
- }
- else {
-
- if(!self.camera.isRecording) {
- self.segmentedControl.hidden = YES;
- self.flashButton.hidden = YES;
- self.switchButton.hidden = YES;
-
- self.snapButton.layer.borderColor = [UIColor redColor].CGColor;
- self.snapButton.backgroundColor = [[UIColor redColor] colorWithAlphaComponent:0.5];
-
- // start recording
- NSURL *outputURL = [[[self applicationDocumentsDirectory]
- URLByAppendingPathComponent:@"test1"] URLByAppendingPathExtension:@"mov"];
- [self.camera startRecordingWithOutputUrl:outputURL];
- }
- else {
- self.segmentedControl.hidden = NO;
- self.flashButton.hidden = NO;
- self.switchButton.hidden = NO;
-
- self.snapButton.layer.borderColor = [UIColor whiteColor].CGColor;
- self.snapButton.backgroundColor = [[UIColor whiteColor] colorWithAlphaComponent:0.5];
-
- [self.camera stopRecording:^(LLSimpleCamera *camera, NSURL *outputFileUrl, NSError *error) {
- VideoViewController *vc = [[VideoViewController alloc] initWithVideoUrl:outputFileUrl];
- [self.navigationController pushViewController:vc animated:YES];
- }];
- }
- }
-}
-
-/* other lifecycle methods */
-- (void)viewWillLayoutSubviews {
- [super viewWillLayoutSubviews];
-
- self.camera.view.frame = self.view.contentBounds;
-
- self.snapButton.center = self.view.contentCenter;
- self.snapButton.bottom = self.view.height - 15;
-
- self.flashButton.center = self.view.contentCenter;
- self.flashButton.top = 5.0f;
-
- self.switchButton.top = 5.0f;
- self.switchButton.right = self.view.width - 5.0f;
-}
-
-- (BOOL)prefersStatusBarHidden {
- return YES;
-}
-
-- (UIInterfaceOrientation) preferredInterfaceOrientationForPresentation {
- return UIInterfaceOrientationPortrait;
-}
-
-- (void)didReceiveMemoryWarning {
- [super didReceiveMemoryWarning];
-}
-
-#pragma mark - Navigation
-
-//#warning - Change your according image view controller here after taking the photo
-
-- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
-{
- if ([segue.identifier isEqualToString:@"Show Image Preview"]) {
- PreviewImageViewController *pivc = segue.destinationViewController;
- pivc.image = (UIImage *)sender;
- }
-}
-
-@end
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/ImagePickerSheet6.4/AnimationController.swift b/ImagePickerSheet6.4/AnimationController.swift
new file mode 100755
index 0000000..3abc0bd
--- /dev/null
+++ b/ImagePickerSheet6.4/AnimationController.swift
@@ -0,0 +1,75 @@
+//
+// AnimationController.swift
+// ImagePickerSheet
+//
+// Created by Laurin Brandner on 25/05/15.
+// Copyright (c) 2015 Laurin Brandner. All rights reserved.
+//
+
+import UIKit
+
+class AnimationController: NSObject, UIViewControllerAnimatedTransitioning {
+
+ let imagePickerSheetController: ImagePickerSheetController
+ let presenting: Bool
+
+ // MARK: - Initialization
+
+ init(imagePickerSheetController: ImagePickerSheetController, presenting: Bool) {
+ self.imagePickerSheetController = imagePickerSheetController
+ self.presenting = presenting
+ }
+
+ // MARK: - UIViewControllerAnimatedTransitioning
+
+ func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval {
+ return 0.3
+ }
+
+ func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
+ if presenting {
+ animatePresentation(transitionContext)
+ }
+ else {
+ animateDismissal(transitionContext)
+ }
+ }
+
+ // MARK: - Animation
+
+ private func animatePresentation(context: UIViewControllerContextTransitioning) {
+ guard let containerView = context.containerView() else {
+ print ("ERROR: container view does not exist")
+ return
+ }
+
+ containerView.addSubview(imagePickerSheetController.view)
+
+ let tableViewOriginY = imagePickerSheetController.tableView.frame.origin.y
+ imagePickerSheetController.tableView.frame.origin.y = containerView.bounds.maxY
+ imagePickerSheetController.backgroundView.alpha = 0
+
+ UIView.animateWithDuration(transitionDuration(context), animations: {
+ self.imagePickerSheetController.tableView.frame.origin.y = tableViewOriginY
+ self.imagePickerSheetController.backgroundView.alpha = 1
+ }, completion: { _ in
+ context.completeTransition(true)
+ })
+ }
+
+ private func animateDismissal(context: UIViewControllerContextTransitioning) {
+ guard let containerView = context.containerView() else {
+ print ("ERROR: container view does not exist")
+ return
+ }
+
+ UIView.animateWithDuration(transitionDuration(context), animations: {
+ self.imagePickerSheetController.tableView.frame.origin.y = containerView.bounds.maxY
+ self.imagePickerSheetController.backgroundView.alpha = 0
+ }, completion: { _ in
+ self.imagePickerSheetController.view.removeFromSuperview()
+ context.completeTransition(true)
+ })
+ }
+
+}
diff --git a/ImagePickerSheet6.4/ImageAction.swift b/ImagePickerSheet6.4/ImageAction.swift
new file mode 100755
index 0000000..c13fe5f
--- /dev/null
+++ b/ImagePickerSheet6.4/ImageAction.swift
@@ -0,0 +1,66 @@
+//
+// ImageAction.swift
+// ImagePickerSheet
+//
+// Created by Laurin Brandner on 24/05/15.
+// Copyright (c) 2015 Laurin Brandner. All rights reserved.
+//
+
+import Foundation
+
+public enum ImageActionStyle {
+ case Default
+ case Cancel
+}
+
+public typealias Title = Int -> String
+
+public class ImageAction {
+
+ public typealias Handler = (ImageAction) -> ()
+ public typealias SecondaryHandler = (ImageAction, Int) -> ()
+
+ let title: String
+ let secondaryTitle: Title
+
+ let style: ImageActionStyle
+
+ let handler: Handler?
+ let secondaryHandler: SecondaryHandler?
+
+ public convenience init(title: String, secondaryTitle: String? = nil, style: ImageActionStyle = .Default, handler: Handler? = nil, secondaryHandler: SecondaryHandler? = nil) {
+ self.init(title: title, secondaryTitle: secondaryTitle.map { string in { _ in string }}, style: style, handler: handler, secondaryHandler: secondaryHandler)
+ }
+
+ public init(title: String, secondaryTitle: Title?, style: ImageActionStyle = .Default, handler: Handler? = nil, var secondaryHandler: SecondaryHandler? = nil) {
+ if let handler = handler where secondaryTitle == nil && secondaryHandler == nil {
+ secondaryHandler = { action, _ in
+ handler(action)
+ }
+ }
+
+ self.title = title
+ self.secondaryTitle = secondaryTitle ?? { _ in title }
+ self.style = style
+ self.handler = handler
+ self.secondaryHandler = secondaryHandler
+ }
+
+ func handle(numberOfPhotos: Int = 0) {
+ if numberOfPhotos > 0 {
+ secondaryHandler?(self, numberOfPhotos)
+ }
+ else {
+ handler?(self)
+ }
+ }
+
+}
+
+func ?? (left: Title?, right: Title) -> Title {
+ if let left = left {
+ return left
+ }
+
+ return right
+}
\ No newline at end of file
diff --git a/ImagePickerSheet6.4/ImageCollectionViewCell.swift b/ImagePickerSheet6.4/ImageCollectionViewCell.swift
new file mode 100755
index 0000000..5e773d0
--- /dev/null
+++ b/ImagePickerSheet6.4/ImageCollectionViewCell.swift
@@ -0,0 +1,53 @@
+//
+// ImageCollectionViewCell.swift
+// ImagePickerSheet
+//
+// Created by Laurin Brandner on 06/09/14.
+// Copyright (c) 2014 Laurin Brandner. All rights reserved.
+//
+
+import UIKit
+
+class ImageCollectionViewCell : UICollectionViewCell {
+
+ let imageView: UIImageView = {
+ let imageView = UIImageView()
+ imageView.contentMode = .ScaleAspectFill
+
+ return imageView
+ }()
+
+ // MARK: - Initialization
+
+ override init(frame: CGRect) {
+ super.init(frame: frame)
+
+ initialize()
+ }
+
+ required init?(coder aDecoder: NSCoder) {
+ super.init(coder: aDecoder)
+
+ initialize()
+ }
+
+ private func initialize() {
+ addSubview(imageView)
+ }
+
+ // MARK: - Other Methods
+
+ override func prepareForReuse() {
+ super.prepareForReuse()
+
+ imageView.image = nil
+ }
+
+ // MARK: - Layout
+
+ override func layoutSubviews() {
+ super.layoutSubviews()
+
+ imageView.frame = bounds
+ }
+}
diff --git a/ImagePickerSheet6.4/ImagePickerCollectionView.swift b/ImagePickerSheet6.4/ImagePickerCollectionView.swift
new file mode 100755
index 0000000..cde76b6
--- /dev/null
+++ b/ImagePickerSheet6.4/ImagePickerCollectionView.swift
@@ -0,0 +1,56 @@
+//
+// ImagePickerCollectionView.swift
+// ImagePickerSheet
+//
+// Created by Laurin Brandner on 07/09/14.
+// Copyright (c) 2014 Laurin Brandner. All rights reserved.
+//
+
+import UIKit
+
+class ImagePickerCollectionView: UICollectionView {
+
+ var bouncing: Bool {
+ return contentOffset.x < -contentInset.left || contentOffset.x + frame.width > contentSize.width + contentInset.right
+ }
+
+ var imagePreviewLayout: ImagePreviewFlowLayout {
+ return collectionViewLayout as! ImagePreviewFlowLayout
+ }
+
+ // MARK: - Initialization
+
+ init() {
+ super.init(frame: CGRectZero, collectionViewLayout: ImagePreviewFlowLayout())
+
+ initialize()
+ }
+
+ required init?(coder aDecoder: NSCoder) {
+ super.init(coder: aDecoder)
+
+ initialize()
+ }
+
+ private func initialize() {
+ panGestureRecognizer.addTarget(self, action: "handlePanGesture:")
+ }
+
+ // MARK: - Panning
+
+ @objc private func handlePanGesture(gestureRecognizer: UIPanGestureRecognizer) {
+ if gestureRecognizer.state == .Ended {
+ let translation = gestureRecognizer.translationInView(self)
+ if translation == CGPointZero {
+ if !bouncing {
+ let possibleIndexPath = indexPathForItemAtPoint(gestureRecognizer.locationInView(self))
+ if let indexPath = possibleIndexPath {
+ selectItemAtIndexPath(indexPath, animated: false, scrollPosition: .None)
+ delegate?.collectionView?(self, didSelectItemAtIndexPath: indexPath)
+ }
+ }
+ }
+ }
+ }
+
+}
diff --git a/ImagePickerSheet6.4/ImagePickerSheetController.h b/ImagePickerSheet6.4/ImagePickerSheetController.h
new file mode 100755
index 0000000..a9f351d
--- /dev/null
+++ b/ImagePickerSheet6.4/ImagePickerSheetController.h
@@ -0,0 +1,19 @@
+//
+// ImagePickerSheetController.h
+// ImagePickerSheetController
+//
+// Created by Laurin Brandner on 26/05/15.
+// Copyright (c) 2015 Laurin Brandner. All rights reserved.
+//
+
+#import
+
+//! Project version number for ImagePickerSheetController.
+FOUNDATION_EXPORT double ImagePickerSheetControllerVersionNumber;
+
+//! Project version string for ImagePickerSheetController.
+FOUNDATION_EXPORT const unsigned char ImagePickerSheetControllerVersionString[];
+
+// In this header, you should import all the public headers of your framework using statements like #import
+
+
diff --git a/ImagePickerSheet6.4/ImagePickerSheetController.swift b/ImagePickerSheet6.4/ImagePickerSheetController.swift
new file mode 100755
index 0000000..c59e6b6
--- /dev/null
+++ b/ImagePickerSheet6.4/ImagePickerSheetController.swift
@@ -0,0 +1,399 @@
+//
+// ImagePickerController.swift
+// ImagePickerSheet
+//
+// Created by Laurin Brandner on 24/05/15.
+// Copyright (c) 2015 Laurin Brandner. All rights reserved.
+//
+
+import Foundation
+import Photos
+
+private let enlargementAnimationDuration = 0.3
+private let tableViewRowHeight: CGFloat = 50.0
+private let tableViewPreviewRowHeight: CGFloat = 140.0
+private let tableViewEnlargedPreviewRowHeight: CGFloat = 243.0
+private let collectionViewInset: CGFloat = 5.0
+private let collectionViewCheckmarkInset: CGFloat = 3.5
+
+public class ImagePickerSheetController: UIViewController, UITableViewDataSource, UITableViewDelegate, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout, UIViewControllerTransitioningDelegate {
+
+ lazy var tableView: UITableView = {
+ let tableView = UITableView()
+ tableView.dataSource = self
+ tableView.delegate = self
+ tableView.alwaysBounceVertical = false
+ tableView.layoutMargins = UIEdgeInsetsZero
+ tableView.separatorInset = UIEdgeInsetsZero
+ tableView.registerClass(ImagePreviewTableViewCell.self, forCellReuseIdentifier: NSStringFromClass(ImagePreviewTableViewCell.self))
+ tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: NSStringFromClass(UITableViewCell.self))
+
+ return tableView
+ }()
+
+ private lazy var collectionView: ImagePickerCollectionView = {
+ let collectionView = ImagePickerCollectionView()
+ collectionView.backgroundColor = .clearColor()
+ collectionView.imagePreviewLayout.sectionInset = UIEdgeInsetsMake(collectionViewInset, collectionViewInset, collectionViewInset, collectionViewInset)
+ collectionView.imagePreviewLayout.showsSupplementaryViews = false
+ collectionView.dataSource = self
+ collectionView.delegate = self
+ collectionView.showsHorizontalScrollIndicator = false
+ collectionView.alwaysBounceHorizontal = true
+ collectionView.registerClass(ImageCollectionViewCell.self, forCellWithReuseIdentifier: NSStringFromClass(ImageCollectionViewCell.self))
+ collectionView.registerClass(PreviewSupplementaryView.self, forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: NSStringFromClass(PreviewSupplementaryView.self))
+
+ return collectionView
+ }()
+
+ lazy var backgroundView: UIView = {
+ let view = UIView()
+ view.backgroundColor = UIColor(white: 0.0, alpha: 0.3961)
+ view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: "cancel"))
+
+ return view
+ }()
+
+ private(set) var actions = [ImageAction]()
+ private var assets = [PHAsset]()
+ private var selectedPhotoIndices = [Int]()
+ private(set) var enlargedPreviews = false
+
+ private var supplementaryViews = [Int: PreviewSupplementaryView]()
+
+ private let imageManager = PHCachingImageManager()
+
+ // MARK: - Initialization
+
+ override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
+ super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
+ initialize()
+ }
+
+ required public init?(coder aDecoder: NSCoder) {
+ super.init(coder: aDecoder)
+ initialize()
+ }
+
+ private func initialize() {
+ modalPresentationStyle = .Custom
+ transitioningDelegate = self
+ }
+
+ // MARK: - View Lifecycle
+
+ override public func loadView() {
+ super.loadView()
+
+ view.addSubview(backgroundView)
+ view.addSubview(tableView)
+ }
+
+ public override func viewWillAppear(animated: Bool) {
+ super.viewWillAppear(animated)
+
+ fetchAssets()
+ }
+
+ // MARK: - UITableViewDataSource
+
+ public func numberOfSectionsInTableView(tableView: UITableView) -> Int {
+ return 2
+ }
+
+ public func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
+ if section == 0 {
+ return 1
+ }
+
+ return actions.count
+ }
+
+ public func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
+ if indexPath.section == 0 {
+ if assets.count > 0 {
+ return enlargedPreviews ? tableViewEnlargedPreviewRowHeight : tableViewPreviewRowHeight
+ }
+
+ return 0
+ }
+
+ return tableViewRowHeight
+ }
+
+ public func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
+ if indexPath.section == 0 {
+ let cell = tableView.dequeueReusableCellWithIdentifier(NSStringFromClass(ImagePreviewTableViewCell.self), forIndexPath: indexPath) as! ImagePreviewTableViewCell
+ cell.collectionView = collectionView
+ cell.separatorInset = UIEdgeInsets(top: 0, left: tableView.bounds.width, bottom: 0, right: 0)
+
+ return cell
+ }
+
+ let action = actions[indexPath.row]
+
+ let cell = tableView.dequeueReusableCellWithIdentifier(NSStringFromClass(UITableViewCell.self), forIndexPath: indexPath)
+ cell.textLabel?.textAlignment = .Center
+ cell.textLabel?.textColor = tableView.tintColor
+ cell.textLabel?.font = UIFont.systemFontOfSize(21)
+ cell.textLabel?.text = selectedPhotoIndices.count > 0 ? action.secondaryTitle(selectedPhotoIndices.count) : action.title
+ cell.layoutMargins = UIEdgeInsetsZero
+
+ return cell
+ }
+
+ // MARK: - UITableViewDelegate
+
+ public func tableView(tableView: UITableView, shouldHighlightRowAtIndexPath indexPath: NSIndexPath) -> Bool {
+ return indexPath.section != 0
+ }
+
+ public func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
+ tableView.deselectRowAtIndexPath(indexPath, animated: true)
+
+ presentingViewController?.dismissViewControllerAnimated(true, completion: nil)
+
+ actions[indexPath.row].handle(selectedPhotoIndices.count)
+ }
+
+ // MARK: - UICollectionViewDataSource
+
+ public func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
+ return assets.count
+ }
+
+ public func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
+ return 1
+ }
+
+ public func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
+ let cell = collectionView.dequeueReusableCellWithReuseIdentifier(NSStringFromClass(ImageCollectionViewCell.self), forIndexPath: indexPath) as! ImageCollectionViewCell
+
+ let asset = assets[indexPath.section]
+ let size = sizeForAsset(asset)
+
+ requestImageForAsset(asset, size: size) { image in
+ cell.imageView.image = image
+ }
+
+ return cell
+ }
+
+ public func collectionView(collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, atIndexPath indexPath: NSIndexPath) -> UICollectionReusableView {
+ let view = collectionView.dequeueReusableSupplementaryViewOfKind(UICollectionElementKindSectionHeader, withReuseIdentifier: NSStringFromClass(PreviewSupplementaryView.self), forIndexPath: indexPath) as! PreviewSupplementaryView
+ view.userInteractionEnabled = false
+ view.buttonInset = UIEdgeInsetsMake(0.0, collectionViewCheckmarkInset, collectionViewCheckmarkInset, 0.0)
+ view.selected = selectedPhotoIndices.contains(indexPath.section)
+
+ supplementaryViews[indexPath.section] = view
+
+ return view
+ }
+
+ // MARK: - UICollectionViewDelegateFlowLayout
+
+ public func collectionView(collectionView: UICollectionView, layout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
+ let asset = assets[indexPath.section]
+
+ return sizeForAsset(asset)
+ }
+
+ public func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
+ let inset = 2.0 * collectionViewCheckmarkInset
+ let size = self.collectionView(collectionView, layout: collectionViewLayout, sizeForItemAtIndexPath: NSIndexPath(forRow: 0, inSection: section))
+ let imageWidth = PreviewSupplementaryView.checkmarkImage?.size.width ?? 0
+
+ return CGSizeMake(imageWidth + inset, size.height)
+ }
+
+ // MARK: - UICollectionViewDelegate
+
+ public func collectionView(collectionView: UICollectionView, willDisplayCell cell: UICollectionViewCell, forItemAtIndexPath indexPath: NSIndexPath) {
+ let nextIndex = indexPath.row+1
+ if nextIndex < assets.count {
+ let asset = assets[nextIndex]
+ let size = sizeForAsset(asset)
+
+ self.prefetchImagesForAsset(asset, size: size)
+ }
+ }
+
+ public func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
+ let selected = selectedPhotoIndices.contains(indexPath.section)
+
+ if !selected {
+ selectedPhotoIndices.append(indexPath.section)
+
+ if !enlargedPreviews {
+ enlargedPreviews = true
+
+ self.collectionView.imagePreviewLayout.invalidationCenteredIndexPath = indexPath
+
+ view.setNeedsLayout()
+ UIView.animateWithDuration(enlargementAnimationDuration, animations: {
+ self.tableView.beginUpdates()
+ self.tableView.endUpdates()
+ self.view.layoutIfNeeded()
+ }, completion: { finished in
+ self.reloadButtonTitles()
+ self.collectionView.imagePreviewLayout.showsSupplementaryViews = true
+ })
+ }
+ else {
+ if let cell = collectionView.cellForItemAtIndexPath(indexPath) {
+ var contentOffset = CGPointMake(cell.frame.midX - collectionView.frame.width / 2.0, 0.0)
+ contentOffset.x = max(contentOffset.x, -collectionView.contentInset.left)
+ contentOffset.x = min(contentOffset.x, collectionView.contentSize.width - collectionView.frame.width + collectionView.contentInset.right)
+
+ collectionView.setContentOffset(contentOffset, animated: true)
+ }
+
+ reloadButtonTitles()
+ }
+ }
+ else {
+ selectedPhotoIndices.removeAtIndex(selectedPhotoIndices.indexOf(indexPath.section)!)
+ reloadButtonTitles()
+ }
+
+ if let sectionView = supplementaryViews[indexPath.section] {
+ sectionView.selected = !selected
+ }
+ }
+
+ // MARK: - Actions
+
+ public func addAction(action: ImageAction) {
+ let cancelActions = actions.filter { $0.style == ImageActionStyle.Cancel }
+ if action.style == .Cancel && cancelActions.count > 0 {
+ // precondition() would be more swifty here, but that's not really testable as of now
+ NSException(name: NSInternalInconsistencyException, reason: "ImagePickerSheetController can only have one action with a style of .Cancel", userInfo: nil).raise()
+ }
+
+ actions.append(action)
+ }
+
+ // MARK: - Photos
+
+ private func sizeForAsset(asset: PHAsset) -> CGSize {
+ let proportion = CGFloat(asset.pixelWidth)/CGFloat(asset.pixelHeight)
+
+ let height: CGFloat = {
+ let rowHeight = self.enlargedPreviews ? tableViewEnlargedPreviewRowHeight : tableViewPreviewRowHeight
+ return rowHeight-2.0*collectionViewInset
+ }()
+
+ return CGSize(width: CGFloat(floorf(Float(proportion*height))), height: height)
+ }
+
+ private func targetSizeForAssetOfSize(size: CGSize) -> CGSize {
+ let scale = UIScreen.mainScreen().scale
+ return CGSize(width: scale*size.width, height: scale*size.height)
+ }
+
+ private func fetchAssets() {
+ let options = PHFetchOptions()
+ options.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
+ let result = PHAsset.fetchAssetsWithMediaType(.Image, options: options)
+
+ result.enumerateObjectsUsingBlock { obj, _, _ in
+ if let asset = obj as? PHAsset where self.assets.count < 50 {
+ self.assets.append(asset)
+ }
+ }
+ }
+
+ private func requestImageForAsset(asset: PHAsset, size: CGSize? = nil, deliveryMode: PHImageRequestOptionsDeliveryMode = .Opportunistic, completion: (image: UIImage?) -> Void) {
+ var targetSize = PHImageManagerMaximumSize
+ if let size = size {
+ targetSize = targetSizeForAssetOfSize(size)
+ }
+
+ let options = PHImageRequestOptions()
+ options.deliveryMode = deliveryMode;
+
+ // Workaround because PHImageManager.requestImageForAsset doesn't work for burst images
+ if asset.representsBurst {
+ imageManager.requestImageDataForAsset(asset, options: options) { data, _, _, _ in
+ guard let safeData = data else {
+ completion(image: nil)
+ return
+ }
+
+ let image = UIImage(data: safeData)
+ completion(image: image)
+ }
+ }
+ else {
+ imageManager.requestImageForAsset(asset, targetSize: targetSize, contentMode: .AspectFill, options: options) { image, _ in
+ completion(image: image)
+ }
+ }
+ }
+
+ private func prefetchImagesForAsset(asset: PHAsset, size: CGSize) {
+ // Not necessary to cache image because PHImageManager won't return burst images
+ if !asset.representsBurst {
+ let targetSize = targetSizeForAssetOfSize(size)
+ imageManager.startCachingImagesForAssets([asset], targetSize: targetSize, contentMode: .AspectFill, options: nil)
+ }
+ }
+
+ public func getSelectedImagesWithCompletion(completion: (images:[UIImage?]) -> Void) {
+ var images = [UIImage?]()
+ var counter = selectedPhotoIndices.count
+
+ for index in selectedPhotoIndices {
+ let asset = assets[index]
+
+ requestImageForAsset(asset, deliveryMode: .HighQualityFormat) { image in
+ images.append(image)
+ counter--
+
+ if counter <= 0 {
+ completion(images: images)
+ }
+ }
+ }
+ }
+
+ // MARK: - Buttons
+
+ private func reloadButtonTitles() {
+ tableView.reloadSections(NSIndexSet(index: 1), withRowAnimation: .None)
+ }
+
+ @objc private func cancel() {
+ presentingViewController?.dismissViewControllerAnimated(true, completion: nil)
+
+ let cancelActions = actions.filter { $0.style == ImageActionStyle.Cancel }
+ if let cancelAction = cancelActions.first {
+ cancelAction.handle(selectedPhotoIndices.count)
+ }
+ }
+
+ // MARK: - Layout
+
+ public override func viewDidLayoutSubviews() {
+ super.viewDidLayoutSubviews()
+
+ backgroundView.frame = view.bounds
+
+ let tableViewHeight = Array(0.. UIViewControllerAnimatedTransitioning? {
+ return AnimationController(imagePickerSheetController: self, presenting: true)
+ }
+
+ public func animationControllerForDismissedController(dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
+ return AnimationController(imagePickerSheetController: self, presenting: false)
+ }
+
+}
diff --git a/ImagePickerSheet6.4/ImagePreviewFlowLayout.swift b/ImagePickerSheet6.4/ImagePreviewFlowLayout.swift
new file mode 100755
index 0000000..e08cbbc
--- /dev/null
+++ b/ImagePickerSheet6.4/ImagePreviewFlowLayout.swift
@@ -0,0 +1,153 @@
+//
+// ImagePreviewFlowLayout.swift
+// ImagePickerSheet
+//
+// Created by Laurin Brandner on 06/09/14.
+// Copyright (c) 2014 Laurin Brandner. All rights reserved.
+//
+
+import UIKit
+
+class ImagePreviewFlowLayout: UICollectionViewFlowLayout {
+
+ var invalidationCenteredIndexPath: NSIndexPath?
+
+ var showsSupplementaryViews: Bool = true {
+ didSet {
+ invalidateLayout()
+ }
+ }
+
+ private var layoutAttributes = [UICollectionViewLayoutAttributes]()
+ private var contentSize = CGSizeZero
+
+ // MARK: - Initialization
+
+ override init() {
+ super.init()
+
+ initialize()
+ }
+
+ required init?(coder aDecoder: NSCoder) {
+ super.init(coder: aDecoder)
+
+ initialize()
+ }
+
+ private func initialize() {
+ scrollDirection = .Horizontal
+ }
+
+ // MARK: - Layout
+
+ override func prepareLayout() {
+ super.prepareLayout()
+
+ layoutAttributes.removeAll(keepCapacity: false)
+ contentSize = CGSizeZero
+
+ if let collectionView = collectionView,
+ dataSource = collectionView.dataSource,
+ delegate = collectionView.delegate as? UICollectionViewDelegateFlowLayout {
+ var origin = CGPoint(x: sectionInset.left, y: sectionInset.top)
+ let numberOfSections = dataSource.numberOfSectionsInCollectionView?(collectionView) ?? 0
+
+ for s in 0 ..< numberOfSections {
+ let indexPath = NSIndexPath(forRow: 0, inSection: s)
+ let size = delegate.collectionView?(collectionView, layout: self, sizeForItemAtIndexPath: indexPath) ?? CGSizeZero
+
+ let attributes = UICollectionViewLayoutAttributes(forCellWithIndexPath: indexPath)
+ attributes.frame = CGRect(origin: origin, size: size)
+ attributes.zIndex = 0
+
+ layoutAttributes.append(attributes)
+
+ origin.x = attributes.frame.maxX + sectionInset.right
+ }
+
+ contentSize = CGSize(width: origin.x, height: collectionView.frame.height)
+ }
+ }
+
+ override func shouldInvalidateLayoutForBoundsChange(newBounds: CGRect) -> Bool {
+ return true
+ }
+
+ override func collectionViewContentSize() -> CGSize {
+ return contentSize
+ }
+
+ override func targetContentOffsetForProposedContentOffset(proposedContentOffset: CGPoint) -> CGPoint {
+ var contentOffset = proposedContentOffset
+ if let indexPath = invalidationCenteredIndexPath {
+ if let collectionView = collectionView {
+ let frame = layoutAttributes[indexPath.section].frame
+ contentOffset.x = frame.midX - collectionView.frame.width / 2.0
+
+ contentOffset.x = max(contentOffset.x, -collectionView.contentInset.left)
+ contentOffset.x = min(contentOffset.x, collectionViewContentSize().width - collectionView.frame.width + collectionView.contentInset.right)
+ }
+ invalidationCenteredIndexPath = nil
+ }
+
+ return super.targetContentOffsetForProposedContentOffset(contentOffset)
+ }
+
+ override func layoutAttributesForElementsInRect(rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
+ return layoutAttributes.filter { CGRectIntersectsRect(rect, $0.frame) }.reduce([UICollectionViewLayoutAttributes]()) { memo, attributes in
+ let supplementaryAttributes = layoutAttributesForSupplementaryViewOfKind(UICollectionElementKindSectionHeader, atIndexPath: attributes.indexPath)
+ return memo + [attributes, supplementaryAttributes]
+ }
+ }
+
+ override func layoutAttributesForItemAtIndexPath(indexPath: NSIndexPath) -> UICollectionViewLayoutAttributes! {
+ return layoutAttributes[indexPath.section]
+ }
+
+ override func layoutAttributesForSupplementaryViewOfKind(elementKind: String, atIndexPath indexPath: NSIndexPath) -> UICollectionViewLayoutAttributes! {
+ if let collectionView = collectionView,
+ dataSource = collectionView.dataSource,
+ delegate = collectionView.delegate as? UICollectionViewDelegateFlowLayout {
+ let itemAttributes = layoutAttributesForItemAtIndexPath(indexPath)
+
+ let inset = collectionView.contentInset
+ let bounds = collectionView.bounds
+ let contentOffset: CGPoint = {
+ var contentOffset = collectionView.contentOffset
+ contentOffset.x += inset.left
+ contentOffset.y += inset.top
+
+ return contentOffset
+ }()
+ let visibleSize: CGSize = {
+ var size = bounds.size
+ size.width -= (inset.left+inset.right)
+
+ return size
+ }()
+ let visibleFrame = CGRect(origin: contentOffset, size: visibleSize)
+
+ let size = delegate.collectionView?(collectionView, layout: self, referenceSizeForHeaderInSection: indexPath.section) ?? CGSizeZero
+ let originX = max(itemAttributes.frame.minX, min(itemAttributes.frame.maxX - size.width, visibleFrame.maxX - size.width))
+
+ let attributes = UICollectionViewLayoutAttributes(forSupplementaryViewOfKind: elementKind, withIndexPath: indexPath)
+ attributes.zIndex = 1
+ attributes.hidden = !showsSupplementaryViews
+ attributes.frame = CGRect(origin: CGPoint(x: originX, y: itemAttributes.frame.minY), size: size)
+
+ return attributes
+ }
+
+ return nil
+ }
+
+ override func initialLayoutAttributesForAppearingItemAtIndexPath(itemIndexPath: NSIndexPath) -> UICollectionViewLayoutAttributes? {
+ return layoutAttributesForItemAtIndexPath(itemIndexPath)
+ }
+
+ override func finalLayoutAttributesForDisappearingItemAtIndexPath(itemIndexPath: NSIndexPath) -> UICollectionViewLayoutAttributes? {
+ return layoutAttributesForItemAtIndexPath(itemIndexPath)
+ }
+
+}
diff --git a/ImagePickerSheet6.4/ImagePreviewTableViewCell.swift b/ImagePickerSheet6.4/ImagePreviewTableViewCell.swift
new file mode 100755
index 0000000..a67d120
--- /dev/null
+++ b/ImagePickerSheet6.4/ImagePreviewTableViewCell.swift
@@ -0,0 +1,44 @@
+//
+// ImagePreviewTableViewCell.swift
+// ImagePickerSheet
+//
+// Created by Laurin Brandner on 06/09/14.
+// Copyright (c) 2014 Laurin Brandner. All rights reserved.
+//
+
+import UIKit
+
+class ImagePreviewTableViewCell : UITableViewCell {
+
+ var collectionView: ImagePickerCollectionView? {
+ willSet {
+ if let collectionView = collectionView {
+ collectionView.removeFromSuperview()
+ }
+
+ if let collectionView = newValue {
+ addSubview(collectionView)
+ }
+ }
+ }
+
+ // MARK: - Other Methods
+
+ override func prepareForReuse() {
+ collectionView = nil
+ }
+
+ // MARK: - Layout
+
+ override func layoutSubviews() {
+ super.layoutSubviews()
+
+ // Setting the frame of the collectionView this large avoids a small animation glitch when resizing the previews. You'll get a beer from @larcus94 if you'll get it to work without this workaround :)
+
+ if let collectionView = collectionView {
+ collectionView.frame = CGRect(x: -bounds.width, y: bounds.minY, width: bounds.width*3, height: bounds.height)
+ collectionView.contentInset = UIEdgeInsetsMake(0.0, bounds.width, 0.0, bounds.width)
+ }
+ }
+
+}
diff --git a/ImagePickerSheet6.4/Images.xcassets/PreviewSupplementaryView-Checkmark-Selected.imageset/Contents.json b/ImagePickerSheet6.4/Images.xcassets/PreviewSupplementaryView-Checkmark-Selected.imageset/Contents.json
new file mode 100755
index 0000000..3abba0e
--- /dev/null
+++ b/ImagePickerSheet6.4/Images.xcassets/PreviewSupplementaryView-Checkmark-Selected.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "PreviewSupplementaryView-Checkmark-Selected.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x",
+ "filename" : "PreviewSupplementaryView-Checkmark-Selected@2x.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x",
+ "filename" : "PreviewSupplementaryView-Checkmark-Selected@3x.png"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/ImagePickerSheet6.4/Images.xcassets/PreviewSupplementaryView-Checkmark-Selected.imageset/PreviewSupplementaryView-Checkmark-Selected.png b/ImagePickerSheet6.4/Images.xcassets/PreviewSupplementaryView-Checkmark-Selected.imageset/PreviewSupplementaryView-Checkmark-Selected.png
new file mode 100755
index 0000000..8d3d970
Binary files /dev/null and b/ImagePickerSheet6.4/Images.xcassets/PreviewSupplementaryView-Checkmark-Selected.imageset/PreviewSupplementaryView-Checkmark-Selected.png differ
diff --git a/ImagePickerSheet6.4/Images.xcassets/PreviewSupplementaryView-Checkmark-Selected.imageset/PreviewSupplementaryView-Checkmark-Selected@2x.png b/ImagePickerSheet6.4/Images.xcassets/PreviewSupplementaryView-Checkmark-Selected.imageset/PreviewSupplementaryView-Checkmark-Selected@2x.png
new file mode 100755
index 0000000..4a09d61
Binary files /dev/null and b/ImagePickerSheet6.4/Images.xcassets/PreviewSupplementaryView-Checkmark-Selected.imageset/PreviewSupplementaryView-Checkmark-Selected@2x.png differ
diff --git a/ImagePickerSheet6.4/Images.xcassets/PreviewSupplementaryView-Checkmark-Selected.imageset/PreviewSupplementaryView-Checkmark-Selected@3x.png b/ImagePickerSheet6.4/Images.xcassets/PreviewSupplementaryView-Checkmark-Selected.imageset/PreviewSupplementaryView-Checkmark-Selected@3x.png
new file mode 100755
index 0000000..2f42084
Binary files /dev/null and b/ImagePickerSheet6.4/Images.xcassets/PreviewSupplementaryView-Checkmark-Selected.imageset/PreviewSupplementaryView-Checkmark-Selected@3x.png differ
diff --git a/ImagePickerSheet6.4/Images.xcassets/PreviewSupplementaryView-Checkmark.imageset/Contents.json b/ImagePickerSheet6.4/Images.xcassets/PreviewSupplementaryView-Checkmark.imageset/Contents.json
new file mode 100755
index 0000000..ae5d3ab
--- /dev/null
+++ b/ImagePickerSheet6.4/Images.xcassets/PreviewSupplementaryView-Checkmark.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "PreviewSupplementaryView-Checkmark.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x",
+ "filename" : "PreviewSupplementaryView-Checkmark@2x.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x",
+ "filename" : "PreviewSupplementaryView-Checkmark@3x.png"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/ImagePickerSheet6.4/Images.xcassets/PreviewSupplementaryView-Checkmark.imageset/PreviewSupplementaryView-Checkmark.png b/ImagePickerSheet6.4/Images.xcassets/PreviewSupplementaryView-Checkmark.imageset/PreviewSupplementaryView-Checkmark.png
new file mode 100755
index 0000000..0106c9d
Binary files /dev/null and b/ImagePickerSheet6.4/Images.xcassets/PreviewSupplementaryView-Checkmark.imageset/PreviewSupplementaryView-Checkmark.png differ
diff --git a/ImagePickerSheet6.4/Images.xcassets/PreviewSupplementaryView-Checkmark.imageset/PreviewSupplementaryView-Checkmark@2x.png b/ImagePickerSheet6.4/Images.xcassets/PreviewSupplementaryView-Checkmark.imageset/PreviewSupplementaryView-Checkmark@2x.png
new file mode 100755
index 0000000..020f970
Binary files /dev/null and b/ImagePickerSheet6.4/Images.xcassets/PreviewSupplementaryView-Checkmark.imageset/PreviewSupplementaryView-Checkmark@2x.png differ
diff --git a/ImagePickerSheet6.4/Images.xcassets/PreviewSupplementaryView-Checkmark.imageset/PreviewSupplementaryView-Checkmark@3x.png b/ImagePickerSheet6.4/Images.xcassets/PreviewSupplementaryView-Checkmark.imageset/PreviewSupplementaryView-Checkmark@3x.png
new file mode 100755
index 0000000..99021d7
Binary files /dev/null and b/ImagePickerSheet6.4/Images.xcassets/PreviewSupplementaryView-Checkmark.imageset/PreviewSupplementaryView-Checkmark@3x.png differ
diff --git a/Spring/Info.plist b/ImagePickerSheet6.4/Info.plist
similarity index 91%
rename from Spring/Info.plist
rename to ImagePickerSheet6.4/Info.plist
index bd4db03..17ad904 100755
--- a/Spring/Info.plist
+++ b/ImagePickerSheet6.4/Info.plist
@@ -7,7 +7,7 @@
CFBundleExecutable$(EXECUTABLE_NAME)CFBundleIdentifier
- designcode.$(PRODUCT_NAME:rfc1034identifier)
+ ch.laurinbrandner.$(PRODUCT_NAME:rfc1034identifier)CFBundleInfoDictionaryVersion6.0CFBundleName
diff --git a/ImagePickerSheet6.4/PreviewSupplementaryView.swift b/ImagePickerSheet6.4/PreviewSupplementaryView.swift
new file mode 100755
index 0000000..6d82e7e
--- /dev/null
+++ b/ImagePickerSheet6.4/PreviewSupplementaryView.swift
@@ -0,0 +1,92 @@
+//
+// PreviewSupplementaryView.swift
+// ImagePickerSheet
+//
+// Created by Laurin Brandner on 06/09/14.
+// Copyright (c) 2014 Laurin Brandner. All rights reserved.
+//
+
+import UIKit
+
+class PreviewSupplementaryView : UICollectionReusableView {
+
+ private let button: UIButton = {
+ let button = UIButton()
+ button.tintColor = .whiteColor()
+ button.userInteractionEnabled = false
+ button.setImage(PreviewSupplementaryView.checkmarkImage, forState: .Normal)
+ button.setImage(PreviewSupplementaryView.selectedCheckmarkImage, forState: .Selected)
+
+ return button
+ }()
+
+ var buttonInset = UIEdgeInsetsZero
+
+ var selected: Bool = false {
+ didSet {
+ button.selected = selected
+ reloadButtonBackgroundColor()
+ }
+ }
+
+ class var checkmarkImage: UIImage? {
+ let bundle = NSBundle(forClass: ImagePickerSheetController.self)
+ let image = UIImage(named: "PreviewSupplementaryView-Checkmark", inBundle: bundle, compatibleWithTraitCollection: nil)
+
+ return image?.imageWithRenderingMode(.AlwaysTemplate)
+ }
+
+ class var selectedCheckmarkImage: UIImage? {
+ let bundle = NSBundle(forClass: ImagePickerSheetController.self)
+ let image = UIImage(named: "PreviewSupplementaryView-Checkmark-Selected", inBundle: bundle, compatibleWithTraitCollection: nil)
+
+ return image?.imageWithRenderingMode(.AlwaysTemplate)
+ }
+
+ // MARK: - Initialization
+
+ override init(frame: CGRect) {
+ super.init(frame: frame)
+
+ initialize()
+ }
+
+ required init?(coder aDecoder: NSCoder) {
+ super.init(coder: aDecoder)
+
+ initialize()
+ }
+
+ private func initialize() {
+ addSubview(button)
+ }
+
+ // MARK: - Other Methods
+
+ override func prepareForReuse() {
+ super.prepareForReuse()
+
+ selected = false
+ }
+
+ override func tintColorDidChange() {
+ super.tintColorDidChange()
+
+ reloadButtonBackgroundColor()
+ }
+
+ private func reloadButtonBackgroundColor() {
+ button.backgroundColor = (selected) ? tintColor : nil
+ }
+
+ // MARK: - Layout
+
+ override func layoutSubviews() {
+ super.layoutSubviews()
+
+ button.sizeToFit()
+ button.frame.origin = CGPointMake(buttonInset.left, CGRectGetHeight(bounds)-CGRectGetHeight(button.frame)-buttonInset.bottom)
+ button.layer.cornerRadius = CGRectGetHeight(button.frame) / 2.0
+ }
+
+}
diff --git a/ImageViewController.h b/ImageViewController.h
deleted file mode 100755
index c31948f..0000000
--- a/ImageViewController.h
+++ /dev/null
@@ -1,13 +0,0 @@
-//
-// ImageViewController.h
-// LLSimpleCameraExample
-//
-// Created by Ömer Faruk Gül on 15/11/14.
-// Copyright (c) 2014 Ömer Faruk Gül. All rights reserved.
-//
-
-#import
-
-@interface ImageViewController : UIViewController
-- (instancetype)initWithImage:(UIImage *)image;
-@end
diff --git a/ImageViewController.m b/ImageViewController.m
deleted file mode 100755
index 4d3ff5c..0000000
--- a/ImageViewController.m
+++ /dev/null
@@ -1,83 +0,0 @@
-//
-// ImageViewController.m
-// LLSimpleCameraExample
-//
-// Created by Ömer Faruk Gül on 15/11/14.
-// Copyright (c) 2014 Ömer Faruk Gül. All rights reserved.
-//
-
-#import "ImageViewController.h"
-#import "ViewUtils.h"
-#import "UIImage+Crop.h"
-
-
-@interface ImageViewController ()
-@property (strong, nonatomic) UIImage *image;
-@property (strong, nonatomic) UIImageView *imageView;
-@property (strong, nonatomic) UILabel *infoLabel;
-@property (strong, nonatomic) UIButton *cancelButton;
-@end
-
-@implementation ImageViewController
-
-- (instancetype)initWithImage:(UIImage *)image {
- self = [super initWithNibName:nil bundle:nil];
- if(self) {
- _image = image;
- }
-
- return self;
-}
-
-- (void)viewDidLoad {
- [super viewDidLoad];
-
- self.imageView.backgroundColor = [UIColor blackColor];
-
- CGRect screenRect = [[UIScreen mainScreen] bounds];
-
- self.imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, screenRect.size.width, screenRect.size.height)];
- self.imageView.contentMode = UIViewContentModeScaleAspectFit;
- self.imageView.backgroundColor = [UIColor clearColor];
- self.imageView.image = self.image;
- [self.view addSubview:self.imageView];
-
- NSString *info = [NSString stringWithFormat:@"Size: %@ - Orientation: %ld", NSStringFromCGSize(self.image.size), (long)self.image.imageOrientation];
-
- self.infoLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 100, 20)];
- self.infoLabel.backgroundColor = [[UIColor darkGrayColor] colorWithAlphaComponent:0.7];
- self.infoLabel.textColor = [UIColor whiteColor];
- self.infoLabel.font = [UIFont fontWithName:@"AvenirNext-Regular" size:13];
- self.infoLabel.textAlignment = NSTextAlignmentCenter;
- self.infoLabel.text = info;
-// [self.view addSubview:self.infoLabel];
-
- UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(viewTapped:)];
- [self.view addGestureRecognizer:tapGesture];
-}
-
-- (void)viewTapped:(UIGestureRecognizer *)gesture {
- [self dismissViewControllerAnimated:NO completion:nil];
-}
-
-- (BOOL)prefersStatusBarHidden {
- return YES;
-}
-
-- (void)viewWillLayoutSubviews {
- [super viewWillLayoutSubviews];
-
- self.imageView.frame = self.view.contentBounds;
-
- [self.infoLabel sizeToFit];
- self.infoLabel.width = self.view.contentBounds.size.width;
- self.infoLabel.top = 0;
- self.infoLabel.left = 0;
-}
-
-- (void)didReceiveMemoryWarning {
- [super didReceiveMemoryWarning];
- // Dispose of any resources that can be recreated.
-}
-
-@end
diff --git a/Images.xcassets/AppIcon.appiconset/Contents.json b/Images.xcassets/AppIcon.appiconset/Contents.json
deleted file mode 100644
index 118c98f..0000000
--- a/Images.xcassets/AppIcon.appiconset/Contents.json
+++ /dev/null
@@ -1,38 +0,0 @@
-{
- "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/Images.xcassets/cam-1.imageset/Contents.json b/Images.xcassets/cam-1.imageset/Contents.json
deleted file mode 100644
index 09a1b42..0000000
--- a/Images.xcassets/cam-1.imageset/Contents.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "images" : [
- {
- "idiom" : "universal",
- "scale" : "1x",
- "filename" : "cam.png"
- },
- {
- "idiom" : "universal",
- "scale" : "2x"
- },
- {
- "idiom" : "universal",
- "scale" : "3x"
- }
- ],
- "info" : {
- "version" : 1,
- "author" : "xcode"
- }
-}
\ No newline at end of file
diff --git a/Images.xcassets/cam-1.imageset/cam.png b/Images.xcassets/cam-1.imageset/cam.png
deleted file mode 100644
index bcf63b7..0000000
Binary files a/Images.xcassets/cam-1.imageset/cam.png and /dev/null differ
diff --git a/Images.xcassets/f1.imageset/Contents.json b/Images.xcassets/f1.imageset/Contents.json
deleted file mode 100644
index 766304b..0000000
--- a/Images.xcassets/f1.imageset/Contents.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "images" : [
- {
- "idiom" : "universal",
- "scale" : "1x",
- "filename" : "f1.jpg"
- },
- {
- "idiom" : "universal",
- "scale" : "2x"
- },
- {
- "idiom" : "universal",
- "scale" : "3x"
- }
- ],
- "info" : {
- "version" : 1,
- "author" : "xcode"
- }
-}
\ No newline at end of file
diff --git a/Images.xcassets/f1.imageset/f1.jpg b/Images.xcassets/f1.imageset/f1.jpg
deleted file mode 100644
index 945c656..0000000
Binary files a/Images.xcassets/f1.imageset/f1.jpg and /dev/null differ
diff --git a/Images.xcassets/f2.imageset/Contents.json b/Images.xcassets/f2.imageset/Contents.json
deleted file mode 100644
index 5ee66fd..0000000
--- a/Images.xcassets/f2.imageset/Contents.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "images" : [
- {
- "idiom" : "universal",
- "scale" : "1x",
- "filename" : "f2.jpg"
- },
- {
- "idiom" : "universal",
- "scale" : "2x"
- },
- {
- "idiom" : "universal",
- "scale" : "3x"
- }
- ],
- "info" : {
- "version" : 1,
- "author" : "xcode"
- }
-}
\ No newline at end of file
diff --git a/Images.xcassets/f2.imageset/f2.jpg b/Images.xcassets/f2.imageset/f2.jpg
deleted file mode 100644
index 548895e..0000000
Binary files a/Images.xcassets/f2.imageset/f2.jpg and /dev/null differ
diff --git a/Images.xcassets/f4.imageset/Contents.json b/Images.xcassets/f4.imageset/Contents.json
deleted file mode 100644
index bbe3524..0000000
--- a/Images.xcassets/f4.imageset/Contents.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "images" : [
- {
- "idiom" : "universal",
- "scale" : "1x",
- "filename" : "f4.jpg"
- },
- {
- "idiom" : "universal",
- "scale" : "2x"
- },
- {
- "idiom" : "universal",
- "scale" : "3x"
- }
- ],
- "info" : {
- "version" : 1,
- "author" : "xcode"
- }
-}
\ No newline at end of file
diff --git a/Images.xcassets/f4.imageset/f4.jpg b/Images.xcassets/f4.imageset/f4.jpg
deleted file mode 100644
index 6332dfd..0000000
Binary files a/Images.xcassets/f4.imageset/f4.jpg and /dev/null differ
diff --git a/Images.xcassets/f5.imageset/Contents.json b/Images.xcassets/f5.imageset/Contents.json
deleted file mode 100644
index 702a676..0000000
--- a/Images.xcassets/f5.imageset/Contents.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "images" : [
- {
- "idiom" : "universal",
- "scale" : "1x",
- "filename" : "f5.jpg"
- },
- {
- "idiom" : "universal",
- "scale" : "2x"
- },
- {
- "idiom" : "universal",
- "scale" : "3x"
- }
- ],
- "info" : {
- "version" : 1,
- "author" : "xcode"
- }
-}
\ No newline at end of file
diff --git a/Images.xcassets/f5.imageset/f5.jpg b/Images.xcassets/f5.imageset/f5.jpg
deleted file mode 100644
index 7aede3f..0000000
Binary files a/Images.xcassets/f5.imageset/f5.jpg and /dev/null differ
diff --git a/Images.xcassets/f6.imageset/Contents.json b/Images.xcassets/f6.imageset/Contents.json
deleted file mode 100644
index 9c77fb3..0000000
--- a/Images.xcassets/f6.imageset/Contents.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "images" : [
- {
- "idiom" : "universal",
- "scale" : "1x",
- "filename" : "f6.jpg"
- },
- {
- "idiom" : "universal",
- "scale" : "2x"
- },
- {
- "idiom" : "universal",
- "scale" : "3x"
- }
- ],
- "info" : {
- "version" : 1,
- "author" : "xcode"
- }
-}
\ No newline at end of file
diff --git a/Images.xcassets/f6.imageset/f6.jpg b/Images.xcassets/f6.imageset/f6.jpg
deleted file mode 100644
index 307f9d0..0000000
Binary files a/Images.xcassets/f6.imageset/f6.jpg and /dev/null differ
diff --git a/Images.xcassets/resticon.imageset/Contents.json b/Images.xcassets/resticon.imageset/Contents.json
deleted file mode 100644
index d5c6709..0000000
--- a/Images.xcassets/resticon.imageset/Contents.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "images" : [
- {
- "idiom" : "universal",
- "scale" : "1x",
- "filename" : "resticon.png"
- },
- {
- "idiom" : "universal",
- "scale" : "2x"
- },
- {
- "idiom" : "universal",
- "scale" : "3x"
- }
- ],
- "info" : {
- "version" : 1,
- "author" : "xcode"
- }
-}
\ No newline at end of file
diff --git a/Images.xcassets/resticon.imageset/resticon.png b/Images.xcassets/resticon.imageset/resticon.png
deleted file mode 100644
index 231020f..0000000
Binary files a/Images.xcassets/resticon.imageset/resticon.png and /dev/null differ
diff --git a/Images.xcassets/resticon2.imageset/Contents.json b/Images.xcassets/resticon2.imageset/Contents.json
deleted file mode 100644
index fea817f..0000000
--- a/Images.xcassets/resticon2.imageset/Contents.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "images" : [
- {
- "idiom" : "universal",
- "scale" : "1x",
- "filename" : "resticon2.png"
- },
- {
- "idiom" : "universal",
- "scale" : "2x"
- },
- {
- "idiom" : "universal",
- "scale" : "3x"
- }
- ],
- "info" : {
- "version" : 1,
- "author" : "xcode"
- }
-}
\ No newline at end of file
diff --git a/Images.xcassets/resticon2.imageset/resticon2.png b/Images.xcassets/resticon2.imageset/resticon2.png
deleted file mode 100644
index 3850998..0000000
Binary files a/Images.xcassets/resticon2.imageset/resticon2.png and /dev/null differ
diff --git a/Images.xcassets/statbackground.imageset/Contents.json b/Images.xcassets/statbackground.imageset/Contents.json
deleted file mode 100644
index 9fe03b0..0000000
--- a/Images.xcassets/statbackground.imageset/Contents.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "images" : [
- {
- "idiom" : "universal",
- "scale" : "1x",
- "filename" : "statbackground.png"
- },
- {
- "idiom" : "universal",
- "scale" : "2x"
- },
- {
- "idiom" : "universal",
- "scale" : "3x"
- }
- ],
- "info" : {
- "version" : 1,
- "author" : "xcode"
- }
-}
\ No newline at end of file
diff --git a/Images.xcassets/statbackground.imageset/statbackground.png b/Images.xcassets/statbackground.imageset/statbackground.png
deleted file mode 100644
index 37fd8e9..0000000
Binary files a/Images.xcassets/statbackground.imageset/statbackground.png and /dev/null differ
diff --git a/LLSimpleCamera.h b/LLSimpleCamera.h
deleted file mode 100755
index c145c5b..0000000
--- a/LLSimpleCamera.h
+++ /dev/null
@@ -1,177 +0,0 @@
-//
-// CameraViewController.h
-// LLSimpleCamera
-//
-// Created by Ömer Faruk Gül on 24/10/14.
-// Copyright (c) 2014 Ömer Farul Gül. All rights reserved.
-//
-
-#import
-#import
-
-typedef enum : NSUInteger {
- CameraPositionBack,
- CameraPositionFront
-} CameraPosition;
-
-typedef enum : NSUInteger {
- // The default state has to be off
- CameraFlashOff,
- CameraFlashOn,
- CameraFlashAuto
-} CameraFlash;
-
-extern NSString *const LLSimpleCameraErrorDomain;
-typedef enum : NSUInteger {
- LLSimpleCameraErrorCodeCameraPermission = 10,
- LLSimpleCameraErrorCodeMicrophonePermission = 11,
- LLSimpleCameraErrorCodeSession = 12,
- LLSimpleCameraErrorCodeVideoNotEnabled = 13
-} LLSimpleCameraErrorCode;
-
-@interface LLSimpleCamera : UIViewController
-
-/**
- * Triggered on device change.
- */
-@property (nonatomic, copy) void (^onDeviceChange)(LLSimpleCamera *camera, AVCaptureDevice *device);
-
-/**
- * Triggered on any kind of error.
- */
-@property (nonatomic, copy) void (^onError)(LLSimpleCamera *camera, NSError *error);
-
-/**
- * Camera quality, set a constants prefixed with AVCaptureSessionPreset.
- * Make sure to call before calling -(void)initialize method, otherwise it would be late.
- */
-@property (copy, nonatomic) NSString *cameraQuality;
-
-/**
- * Camera flash mode.
- */
-@property (nonatomic, readonly) CameraFlash flash;
-
-/**
- * Position of the camera.
- */
-@property (nonatomic) CameraPosition position;
-
-/**
- * Boolean value to indicate if the video is enabled.
- */
-@property (nonatomic, getter=isVideoEnabled) BOOL videoEnabled;
-
-/**
- * Boolean value to indicate if the camera is recording a video at the current moment.
- */
-@property (nonatomic, getter=isRecording) BOOL recording;
-
-/**
- * Fixess the orientation after the image is captured is set to Yes.
- * see: http://stackoverflow.com/questions/5427656/ios-uiimagepickercontroller-result-image-orientation-after-upload
- */
-@property (nonatomic) BOOL fixOrientationAfterCapture;
-
-/**
- * Set NO if you don't want ot enable user triggered focusing. Enabled by default.
- */
-@property (nonatomic) BOOL tapToFocus;
-
-/**
- * Set YES if you your view controller does not allow autorotation,
- * however you want to take the device rotation into account no matter what. Disabled by default.
- */
-@property (nonatomic) BOOL useDeviceOrientation;
-
-/**
- * Use this method to request camera permission before initalizing LLSimpleCamera.
- */
-+ (void)requestCameraPermission:(void (^)(BOOL granted))completionBlock;
-
-/**
- * Use this method to request microphone permission before initalizing LLSimpleCamera.
- */
-+ (void)requestMicrophonePermission:(void (^)(BOOL granted))completionBlock;
-
-/**
- * Returns an instance of LLSimpleCamera with the given quality.
- * Quality parameter could be any variable starting with AVCaptureSessionPreset.
- */
-- (instancetype)initWithQuality:(NSString *)quality position:(CameraPosition)position videoEnabled:(BOOL)videoEnabled;
-
-/**
- * Returns an instance of LLSimpleCamera with quality "AVCaptureSessionPresetHigh" and position "CameraPositionBack".
- * @param videEnabled: Set to YES to enable video recording.
- */
-- (instancetype)initWithVideoEnabled:(BOOL)videoEnabled;
-
-/**
- * Starts running the camera session.
- */
-- (void)start;
-
-/**
- * Stops the running camera session. Needs to be called when the app doesn't show the view.
- */
-- (void)stop;
-
-/**
- * Capture an image.
- * @param onCapture a block triggered after the capturing the photo.
- * @param exactSeenImage If set YES, then the image is cropped to the exact size as the preview. So you get exactly what you see.
- */
--(void)capture:(void (^)(LLSimpleCamera *camera, UIImage *image, NSDictionary *metadata, NSError *error))onCapture exactSeenImage:(BOOL)exactSeenImage;
-
-/**
- * Capture an image.
- * @param onCapture a block triggered after the capturing the photo.
- */
--(void)capture:(void (^)(LLSimpleCamera *camera, UIImage *image, NSDictionary *metadata, NSError *error))onCapture;
-
-/*
- * Start recording a video. Video is saved to the given url.
- */
-- (void)startRecordingWithOutputUrl:(NSURL *)url;
-
-/**
- * Stop recording video with a completion block.
- */
-- (void)stopRecording:(void (^)(LLSimpleCamera *camera, NSURL *outputFileUrl, NSError *error))completionBlock;
-
-/**
- * Attaches the LLSimpleCamera to another view controller with a frame. It basically adds the LLSimpleCamera as a
- * child vc to the given vc.
- * @param vc A view controller.
- * @param frame The frame of the camera.
- */
-- (void)attachToViewController:(UIViewController *)vc withFrame:(CGRect)frame;
-
-/**
- * Changes the posiition of the camera (either back or front) and returns the final position.
- */
-- (CameraPosition)togglePosition;
-
-/**
- * Update the flash mode of the camera. Returns true if it is successful. Otherwise false.
- */
-- (BOOL)updateFlashMode:(CameraFlash)cameraFlash;
-
-/**
- * Checks if flash is avilable for the currently active device.
- */
-- (BOOL)isFlashAvailable;
-
-/**
- * Checks if torch (flash for video) is avilable for the currently active device.
- */
-- (BOOL)isTorchAvailable;
-
-/**
- * Alter the layer and the animation displayed when the user taps on screen.
- * @param layer Layer to be displayed
- * @param animation to be applied after the layer is shown
- */
-- (void)alterFocusBox:(CALayer *)layer animation:(CAAnimation *)animation;
-
-@end
diff --git a/LLSimpleCamera.m b/LLSimpleCamera.m
deleted file mode 100755
index 20c902b..0000000
--- a/LLSimpleCamera.m
+++ /dev/null
@@ -1,756 +0,0 @@
-//
-// CameraViewController.m
-// LLSimpleCamera
-//
-// Created by Ömer Faruk Gül on 24/10/14.
-// Copyright (c) 2014 Ömer Faruk Gül. All rights reserved.
-//
-
-#import "LLSimpleCamera.h"
-#import
-#import "UIImage+FixOrientation.h"
-
-@interface LLSimpleCamera ()
-@property (strong, nonatomic) UIView *preview;
-@property (strong, nonatomic) AVCaptureStillImageOutput *stillImageOutput;
-@property (strong, nonatomic) AVCaptureSession *session;
-@property (strong, nonatomic) AVCaptureDevice *videoCaptureDevice;
-@property (strong, nonatomic) AVCaptureDevice *audioCaptureDevice;
-@property (strong, nonatomic) AVCaptureDeviceInput *videoDeviceInput;
-@property (strong, nonatomic) AVCaptureDeviceInput *audioDeviceInput;
-@property (strong, nonatomic) AVCaptureVideoPreviewLayer *captureVideoPreviewLayer;
-@property (strong, nonatomic) UITapGestureRecognizer *tapGesture;
-@property (strong, nonatomic) CALayer *focusBoxLayer;
-@property (strong, nonatomic) CAAnimation *focusBoxAnimation;
-@property (strong, nonatomic) AVCaptureMovieFileOutput *movieFileOutput;
-@property (nonatomic, copy) void (^didRecord)(LLSimpleCamera *camera, NSURL *outputFileUrl, NSError *error);
-@end
-
-NSString *const LLSimpleCameraErrorDomain = @"LLSimpleCameraErrorDomain";
-
-@implementation LLSimpleCamera
-
-- (instancetype)init {
- self = [self initWithVideoEnabled:NO];
- if(self) {
- }
-
- return self;
-}
-
-- (instancetype)initWithVideoEnabled:(BOOL)videoEnabled {
- self = [self initWithQuality:AVCaptureSessionPresetHigh position:CameraPositionBack videoEnabled:videoEnabled];
- if(self) {
- }
-
- return self;
-}
-
-- (instancetype)initWithQuality:(NSString *)quality position:(CameraPosition)position videoEnabled:(BOOL)videoEnabled {
- self = [super initWithNibName:nil bundle:nil];
- if(self) {
- _cameraQuality = quality;
- _position = position;
- _fixOrientationAfterCapture = NO;
- _tapToFocus = YES;
- _useDeviceOrientation = NO;
- _flash = CameraFlashOff;
- _videoEnabled = videoEnabled;
- _recording = NO;
- }
-
- return self;
-}
-
-- (void)viewDidLoad {
- [super viewDidLoad];
-
- self.view.backgroundColor = [UIColor clearColor];
- self.view.autoresizingMask = UIViewAutoresizingNone;
-
- self.preview = [[UIView alloc] initWithFrame:CGRectZero];
- self.preview.backgroundColor = [UIColor clearColor];
- [self.view addSubview:self.preview];
-
- // tap to focus
- self.tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(previewTapped:)];
- self.tapGesture.numberOfTapsRequired = 1;
- [self.tapGesture setDelaysTouchesEnded:NO];
- [self.preview addGestureRecognizer:self.tapGesture];
-
- // add focus box to view
- [self addDefaultFocusBox];
-}
-
-- (void)addDefaultFocusBox {
-
- CALayer *focusBox = [[CALayer alloc] init];
- focusBox.cornerRadius = 5.0f;
- focusBox.bounds = CGRectMake(0.0f, 0.0f, 70, 60);
- focusBox.borderWidth = 3.0f;
- focusBox.borderColor = [[UIColor yellowColor] CGColor];
- focusBox.opacity = 0.0f;
- [self.view.layer addSublayer:focusBox];
-
- CABasicAnimation *focusBoxAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"];
- focusBoxAnimation.duration = 0.75;
- focusBoxAnimation.autoreverses = NO;
- focusBoxAnimation.repeatCount = 0.0;
- focusBoxAnimation.fromValue = [NSNumber numberWithFloat:1.0];
- focusBoxAnimation.toValue = [NSNumber numberWithFloat:0.0];
-
- [self alterFocusBox:focusBox animation:focusBoxAnimation];
-}
-
-- (void)alterFocusBox:(CALayer *)layer animation:(CAAnimation *)animation {
- self.focusBoxLayer = layer;
- self.focusBoxAnimation = animation;
-}
-
-- (void)attachToViewController:(UIViewController *)vc withFrame:(CGRect)frame {
- [vc.view addSubview:self.view];
- [vc addChildViewController:self];
- [self didMoveToParentViewController:vc];
-
- vc.view.frame = frame;
-}
-
-# pragma mark Touch Delegate
-
-- (void) previewTapped: (UIGestureRecognizer *) gestureRecognizer
-{
- if(!self.tapToFocus) {
- return;
- }
-
- CGPoint touchedPoint = (CGPoint) [gestureRecognizer locationInView:self.preview];
-
- // focus
- CGPoint pointOfInterest = [self convertToPointOfInterestFromViewCoordinates:touchedPoint];
- [self focusAtPoint:pointOfInterest];
-
- // show the box
- [self showFocusBox:touchedPoint];
-}
-
-#pragma mark Camera Actions
-
-- (void)start {
- [LLSimpleCamera requestCameraPermission:^(BOOL granted) {
- if(granted) {
- // request microphone permission if video is enabled
- if(self.videoEnabled) {
- [LLSimpleCamera requestMicrophonePermission:^(BOOL granted) {
- if(granted) {
- [self initialize];
- }
- else {
- NSError *error = [NSError errorWithDomain:LLSimpleCameraErrorDomain
- code:LLSimpleCameraErrorCodeMicrophonePermission
- userInfo:nil];
- if(self.onError) {
- self.onError(self, error);
- }
- }
- }];
- }
- else {
- [self initialize];
- }
- }
- else {
- NSError *error = [NSError errorWithDomain:LLSimpleCameraErrorDomain
- code:LLSimpleCameraErrorCodeCameraPermission
- userInfo:nil];
- if(self.onError) {
- self.onError(self, error);
- }
- }
- }];
-}
-
-- (void)initialize {
- if(!_session) {
- _session = [[AVCaptureSession alloc] init];
- _session.sessionPreset = self.cameraQuality;
-
- // preview layer
- CGRect bounds = self.preview.layer.bounds;
- _captureVideoPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:self.session];
- _captureVideoPreviewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
- _captureVideoPreviewLayer.bounds = bounds;
- _captureVideoPreviewLayer.position = CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds));
- [self.preview.layer addSublayer:_captureVideoPreviewLayer];
-
- AVCaptureDevicePosition devicePosition;
- switch (self.position) {
- case CameraPositionBack:
- devicePosition = AVCaptureDevicePositionBack;
- break;
- case CameraPositionFront:
- devicePosition = AVCaptureDevicePositionFront;
- break;
- default:
- devicePosition = AVCaptureDevicePositionUnspecified;
- break;
- }
-
- if(devicePosition == AVCaptureDevicePositionUnspecified) {
- _videoCaptureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
- }
- else {
- _videoCaptureDevice = [self cameraWithPosition:devicePosition];
- }
-
- NSError *error = nil;
- _videoDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:_videoCaptureDevice error:&error];
-
- if (!_videoDeviceInput) {
- if(self.onError) {
- self.onError(self, error);
- }
- return;
- }
-
- if([self.session canAddInput:_videoDeviceInput]) {
- [self.session addInput:_videoDeviceInput];
- }
-
- // add audio if video is enabled
- if(self.videoEnabled) {
- _audioCaptureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio];
- _audioDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:_audioCaptureDevice error:&error];
- if (!_audioDeviceInput) {
- if(self.onError) {
- self.onError(self, error);
- }
- }
-
- if([self.session canAddInput:_audioDeviceInput]) {
- [self.session addInput:_audioDeviceInput];
- }
-
- _movieFileOutput = [[AVCaptureMovieFileOutput alloc] init];
- if([self.session canAddOutput:_movieFileOutput]) {
- [self.session addOutput:_movieFileOutput];
- }
- }
-
-
- self.stillImageOutput = [[AVCaptureStillImageOutput alloc] init];
- NSDictionary *outputSettings = [[NSDictionary alloc] initWithObjectsAndKeys: AVVideoCodecJPEG, AVVideoCodecKey, nil];
- [self.stillImageOutput setOutputSettings:outputSettings];
- [self.session addOutput:self.stillImageOutput];
- }
-
- //if we had disabled the connection on capture, re-enable it
- if (![self.captureVideoPreviewLayer.connection isEnabled]) {
- [self.captureVideoPreviewLayer.connection setEnabled:YES];
- }
-
- [self.session startRunning];
-}
-
-- (void)stop {
- [self.session stopRunning];
-}
-
-
-#pragma mark Image Methods
-
--(void)capture:(void (^)(LLSimpleCamera *camera, UIImage *image, NSDictionary *metadata, NSError *error))onCapture exactSeenImage:(BOOL)exactSeenImage {
-
- if(!self.session) {
- NSError *error = [NSError errorWithDomain:LLSimpleCameraErrorDomain
- code:LLSimpleCameraErrorCodeSession
- userInfo:nil];
- onCapture(self, nil, nil, error);
- return;
- }
-
- // get connection and set orientation
- AVCaptureConnection *videoConnection = [self captureConnection];
- videoConnection.videoOrientation = [self orientationForConnection];
-
- // freeze the screen
- [self.captureVideoPreviewLayer.connection setEnabled:NO];
-
- [self.stillImageOutput captureStillImageAsynchronouslyFromConnection:videoConnection completionHandler: ^(CMSampleBufferRef imageSampleBuffer, NSError *error) {
-
- UIImage *image = nil;
- NSDictionary *metadata = nil;
-
- // check if we got the image buffer
- if (imageSampleBuffer != NULL) {
- CFDictionaryRef exifAttachments = CMGetAttachment(imageSampleBuffer, kCGImagePropertyExifDictionary, NULL);
- if(exifAttachments) {
- metadata = (__bridge NSDictionary*)exifAttachments;
- }
-
- NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageSampleBuffer];
- image = [[UIImage alloc] initWithData:imageData];
-
- if(exactSeenImage) {
- image = [self cropImageUsingPreviewBounds:image];
- }
-
- if(self.fixOrientationAfterCapture) {
- image = [image fixOrientation];
- }
- }
-
- // trigger the block
- if(onCapture) {
- onCapture(self, image, metadata, error);
- }
- }];
-}
-
--(void)capture:(void (^)(LLSimpleCamera *camera, UIImage *image, NSDictionary *metadata, NSError *error))onCapture {
- [self capture:onCapture exactSeenImage:NO];
-}
-
-#pragma mark Video Methods
-
-- (void)startRecordingWithOutputUrl:(NSURL *)url {
-
- // check if video is enabled
- if(!self.videoEnabled) {
- NSError *error = [NSError errorWithDomain:LLSimpleCameraErrorDomain
- code:LLSimpleCameraErrorCodeVideoNotEnabled
- userInfo:nil];
- if(self.onError) {
- self.onError(self, error);
- }
-
- return;
- }
-
- if(self.flash == CameraFlashOn) {
- [self enableTorch:YES];
- }
- [self.movieFileOutput startRecordingToOutputFileURL:url recordingDelegate:self];
-}
-
-- (void)stopRecording:(void (^)(LLSimpleCamera *camera, NSURL *outputFileUrl, NSError *error))completionBlock {
-
- if(!self.videoEnabled) {
- return;
- }
-
- self.didRecord = completionBlock;
- [self.movieFileOutput stopRecording];
-}
-
-- (void)captureOutput:(AVCaptureFileOutput *)captureOutput didStartRecordingToOutputFileAtURL:(NSURL *)fileURL fromConnections:(NSArray *)connections {
- self.recording = YES;
-}
-
-- (void)captureOutput:(AVCaptureFileOutput *)captureOutput didFinishRecordingToOutputFileAtURL:(NSURL *)outputFileURL fromConnections:(NSArray *)connections error:(NSError *)error {
-
- self.recording = NO;
- [self enableTorch:NO];
-
- if(self.didRecord) {
- self.didRecord(self, outputFileURL, error);
- }
-}
-
-- (void)enableTorch:(BOOL)enabled {
- // check if the device has a toch, otherwise don't even bother to take any action.
- if([self isTorchAvailable]) {
- [self.session beginConfiguration];
- [self.videoCaptureDevice lockForConfiguration:nil];
- if (enabled) {
- [self.videoCaptureDevice setTorchMode:AVCaptureTorchModeOn];
- } else {
- [self.videoCaptureDevice setTorchMode:AVCaptureTorchModeOff];
- }
- [self.videoCaptureDevice unlockForConfiguration];
- [self.session commitConfiguration];
- }
-}
-
-#pragma mark Helper Methods
-
-- (UIImage *)cropImageUsingPreviewBounds:(UIImage *)image {
-
- CGRect previewBounds = self.captureVideoPreviewLayer.bounds;
- CGRect outputRect = [self.captureVideoPreviewLayer metadataOutputRectOfInterestForRect:previewBounds];
-
- CGImageRef takenCGImage = image.CGImage;
- size_t width = CGImageGetWidth(takenCGImage);
- size_t height = CGImageGetHeight(takenCGImage);
- CGRect cropRect = CGRectMake(outputRect.origin.x * width, outputRect.origin.y * height,
- outputRect.size.width * width, outputRect.size.height * height);
-
- CGImageRef cropCGImage = CGImageCreateWithImageInRect(takenCGImage, cropRect);
- image = [UIImage imageWithCGImage:cropCGImage scale:1 orientation:image.imageOrientation];
- CGImageRelease(cropCGImage);
-
- return image;
-}
-
-- (AVCaptureConnection *)captureConnection {
-
- AVCaptureConnection *videoConnection = nil;
- for (AVCaptureConnection *connection in self.stillImageOutput.connections) {
- for (AVCaptureInputPort *port in [connection inputPorts]) {
- if ([[port mediaType] isEqual:AVMediaTypeVideo]) {
- videoConnection = connection;
- break;
- }
- }
- if (videoConnection) {
- break;
- }
- }
-
- return videoConnection;
-}
-
-- (void)setVideoCaptureDevice:(AVCaptureDevice *)videoCaptureDevice {
- _videoCaptureDevice = videoCaptureDevice;
-
- if(videoCaptureDevice.flashMode == AVCaptureFlashModeAuto) {
- _flash = CameraFlashAuto;
- }
- else if(videoCaptureDevice.flashMode == AVCaptureFlashModeOn) {
- _flash = CameraFlashOn;
- }
- else if(videoCaptureDevice.flashMode == AVCaptureFlashModeOff) {
- _flash = CameraFlashOff;
- }
- else {
- _flash = CameraFlashOff;
- }
-
- // trigger block
- if(self.onDeviceChange) {
- self.onDeviceChange(self, videoCaptureDevice);
- }
-}
-
-- (BOOL)isFlashAvailable {
- return self.videoCaptureDevice.hasFlash && self.videoCaptureDevice.isFlashAvailable;
-}
-
-- (BOOL)isTorchAvailable {
- return self.videoCaptureDevice.hasTorch && self.videoCaptureDevice.isTorchAvailable;
-}
-
-- (BOOL)updateFlashMode:(CameraFlash)cameraFlash {
- if(!self.session)
- return NO;
-
- AVCaptureFlashMode flashMode;
-
- if(cameraFlash == CameraFlashOn) {
- flashMode = AVCaptureFlashModeOn;
- }
- else if(cameraFlash == CameraFlashAuto) {
- flashMode = AVCaptureFlashModeAuto;
- }
- else {
- flashMode = AVCaptureFlashModeOff;
- }
-
-
- if([self.videoCaptureDevice isFlashModeSupported:flashMode]) {
- NSError *error;
- if([self.videoCaptureDevice lockForConfiguration:&error]) {
- self.videoCaptureDevice.flashMode = flashMode;
- [self.videoCaptureDevice unlockForConfiguration];
-
- _flash = cameraFlash;
- return YES;
- }
- else {
- if(self.onError) {
- self.onError(self, error);
- }
- return NO;
- }
- }
- else {
- return NO;
- }
-}
-
-- (CameraPosition)togglePosition {
- if(!self.session) {
- return self.position;
- }
-
- if(self.position == CameraPositionBack) {
- self.cameraPosition = CameraPositionFront;
- }
- else {
- self.cameraPosition = CameraPositionBack;
- }
-
- return self.position;
-}
-
-- (void)setCameraPosition:(CameraPosition)cameraPosition
-{
- if(_position == cameraPosition || !self.session) {
- return;
- }
-
- [self.session beginConfiguration];
-
- // remove existing input
- [self.session removeInput:self.videoDeviceInput];
-
- // get new input
- AVCaptureDevice *device = nil;
- if(self.videoDeviceInput.device.position == AVCaptureDevicePositionBack) {
- device = [self cameraWithPosition:AVCaptureDevicePositionFront];
- }
- else {
- device = [self cameraWithPosition:AVCaptureDevicePositionBack];
- }
-
- if(!device) {
- return;
- }
-
- // add input to session
- NSError *error = nil;
- AVCaptureDeviceInput *videoInput = [[AVCaptureDeviceInput alloc] initWithDevice:device error:&error];
- if(error) {
- if(self.onError) {
- self.onError(self, error);
- }
- [self.session commitConfiguration];
- return;
- }
-
- _position = cameraPosition;
-
- [self.session addInput:videoInput];
- [self.session commitConfiguration];
-
- self.videoCaptureDevice = device;
- self.videoDeviceInput = videoInput;
-}
-
-
-// Find a camera with the specified AVCaptureDevicePosition, returning nil if one is not found
-- (AVCaptureDevice *) cameraWithPosition:(AVCaptureDevicePosition) position
-{
- NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
- for (AVCaptureDevice *device in devices) {
- if (device.position == position) return device;
- }
- return nil;
-}
-
-#pragma mark Focus
-
-- (void) focusAtPoint:(CGPoint)point
-{
- //NSLog(@"Focusing at point %@", NSStringFromCGPoint(point));
-
- AVCaptureDevice *device = self.videoCaptureDevice;
- if (device.isFocusPointOfInterestSupported && [device isFocusModeSupported:AVCaptureFocusModeAutoFocus]) {
- NSError *error;
- if ([device lockForConfiguration:&error]) {
- device.focusPointOfInterest = point;
- device.focusMode = AVCaptureFocusModeAutoFocus;
- [device unlockForConfiguration];
- }
-
- if(error && self.onError) {
- self.onError(self, error);
- }
- }
-}
-
-- (void)showFocusBox:(CGPoint)point {
-
- if(self.focusBoxLayer) {
- // clear animations
- [self.focusBoxLayer removeAllAnimations];
-
- // move layer to the touc point
- [CATransaction begin];
- [CATransaction setValue: (id) kCFBooleanTrue forKey: kCATransactionDisableActions];
- self.focusBoxLayer.position = point;
- [CATransaction commit];
- }
-
- if(self.focusBoxAnimation) {
- // run the animation
- [self.focusBoxLayer addAnimation:self.focusBoxAnimation forKey:@"animateOpacity"];
- }
-}
-
-- (CGPoint)convertToPointOfInterestFromViewCoordinates:(CGPoint)viewCoordinates
-{
- AVCaptureVideoPreviewLayer *previewLayer = self.captureVideoPreviewLayer;
-
- CGPoint pointOfInterest = CGPointMake(.5f, .5f);
- CGSize frameSize = previewLayer.frame.size;
-
- if ( [previewLayer.videoGravity isEqualToString:AVLayerVideoGravityResize] ) {
- pointOfInterest = CGPointMake(viewCoordinates.y / frameSize.height, 1.f - (viewCoordinates.x / frameSize.width));
- } else {
- CGRect cleanAperture;
- for (AVCaptureInputPort *port in [self.videoDeviceInput ports]) {
- if (port.mediaType == AVMediaTypeVideo) {
- cleanAperture = CMVideoFormatDescriptionGetCleanAperture([port formatDescription], YES);
- CGSize apertureSize = cleanAperture.size;
- CGPoint point = viewCoordinates;
-
- CGFloat apertureRatio = apertureSize.height / apertureSize.width;
- CGFloat viewRatio = frameSize.width / frameSize.height;
- CGFloat xc = .5f;
- CGFloat yc = .5f;
-
- if ( [previewLayer.videoGravity isEqualToString:AVLayerVideoGravityResizeAspect] ) {
- if (viewRatio > apertureRatio) {
- CGFloat y2 = frameSize.height;
- CGFloat x2 = frameSize.height * apertureRatio;
- CGFloat x1 = frameSize.width;
- CGFloat blackBar = (x1 - x2) / 2;
- if (point.x >= blackBar && point.x <= blackBar + x2) {
- xc = point.y / y2;
- yc = 1.f - ((point.x - blackBar) / x2);
- }
- } else {
- CGFloat y2 = frameSize.width / apertureRatio;
- CGFloat y1 = frameSize.height;
- CGFloat x2 = frameSize.width;
- CGFloat blackBar = (y1 - y2) / 2;
- if (point.y >= blackBar && point.y <= blackBar + y2) {
- xc = ((point.y - blackBar) / y2);
- yc = 1.f - (point.x / x2);
- }
- }
- } else if ([previewLayer.videoGravity isEqualToString:AVLayerVideoGravityResizeAspectFill]) {
- if (viewRatio > apertureRatio) {
- CGFloat y2 = apertureSize.width * (frameSize.width / apertureSize.height);
- xc = (point.y + ((y2 - frameSize.height) / 2.f)) / y2;
- yc = (frameSize.width - point.x) / frameSize.width;
- } else {
- CGFloat x2 = apertureSize.height * (frameSize.height / apertureSize.width);
- yc = 1.f - ((point.x + ((x2 - frameSize.width) / 2)) / x2);
- xc = point.y / frameSize.height;
- }
- }
-
- pointOfInterest = CGPointMake(xc, yc);
- break;
- }
- }
- }
-
- return pointOfInterest;
-}
-
-
-#pragma mark - Controller Lifecycle
-
-- (void)viewWillAppear:(BOOL)animated {
- [super viewWillAppear:animated];
-}
-
-- (void)viewWillDisappear:(BOOL)animated {
- [super viewWillDisappear:animated];
-}
-
-- (void)viewWillLayoutSubviews {
- [super viewWillLayoutSubviews];
-
-// NSLog(@"layout cameraVC : %d", self.interfaceOrientation);
-
- self.preview.frame = CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height);
-
- CGRect bounds = self.preview.bounds;
- self.captureVideoPreviewLayer.bounds = bounds;
- self.captureVideoPreviewLayer.position = CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds));
-
- self.captureVideoPreviewLayer.connection.videoOrientation = [self orientationForConnection];
-}
-
-- (AVCaptureVideoOrientation)orientationForConnection
-{
- AVCaptureVideoOrientation videoOrientation = AVCaptureVideoOrientationPortrait;
-
- if(self.useDeviceOrientation) {
- switch ([UIDevice currentDevice].orientation) {
- case UIDeviceOrientationLandscapeLeft:
- // yes we to the right, this is not bug!
- videoOrientation = AVCaptureVideoOrientationLandscapeRight;
- break;
- case UIDeviceOrientationLandscapeRight:
- videoOrientation = AVCaptureVideoOrientationLandscapeLeft;
- break;
- case UIDeviceOrientationPortraitUpsideDown:
- videoOrientation = AVCaptureVideoOrientationPortraitUpsideDown;
- break;
- default:
- videoOrientation = AVCaptureVideoOrientationPortrait;
- break;
- }
- }
- else {
- switch (self.interfaceOrientation) {
- case UIInterfaceOrientationLandscapeLeft:
- videoOrientation = AVCaptureVideoOrientationLandscapeLeft;
- break;
- case UIInterfaceOrientationLandscapeRight:
- videoOrientation = AVCaptureVideoOrientationLandscapeRight;
- break;
- case UIInterfaceOrientationPortraitUpsideDown:
- videoOrientation = AVCaptureVideoOrientationPortraitUpsideDown;
- break;
- default:
- videoOrientation = AVCaptureVideoOrientationPortrait;
- break;
- }
- }
-
- return videoOrientation;
-}
-
-- (void)didReceiveMemoryWarning {
- [super didReceiveMemoryWarning];
- // Dispose of any resources that can be recreated.
-}
-
-
-#pragma mark static methods
-
-+ (void)requestCameraPermission:(void (^)(BOOL granted))completionBlock {
- if ([AVCaptureDevice respondsToSelector:@selector(requestAccessForMediaType: completionHandler:)]) {
- [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
- // return to main thread
- dispatch_async(dispatch_get_main_queue(), ^{
- if(completionBlock) {
- completionBlock(granted);
- }
- });
- }];
- } else {
- completionBlock(YES);
- }
-
-}
-
-+ (void)requestMicrophonePermission:(void (^)(BOOL granted))completionBlock {
- if([[AVAudioSession sharedInstance] respondsToSelector:@selector(requestRecordPermission:)]) {
- [[AVAudioSession sharedInstance] requestRecordPermission:^(BOOL granted) {
- // return to main thread
- dispatch_async(dispatch_get_main_queue(), ^{
- if(completionBlock) {
- completionBlock(granted);
- }
- });
- }];
- }
-}
-
-@end
\ No newline at end of file
diff --git a/LoginVC.swift b/LoginVC.swift
deleted file mode 100644
index 11c95f0..0000000
--- a/LoginVC.swift
+++ /dev/null
@@ -1,108 +0,0 @@
-//
-// LoginVC.swift
-// Dindr
-//
-// Created by lsecrease on 8/15/15.
-// Copyright (c) 2015 ImagineME. All rights reserved.
-//
-
-import UIKit
-
-class LoginVC: UIViewController, UITextFieldDelegate, UIAlertViewDelegate {
-
- @IBOutlet weak var usernameTextField: UITextField!
- @IBOutlet weak var passwordTextField: UITextField!
-
- @IBOutlet weak var loginButton: DesignableButton!
-
- override func viewWillAppear(animated: Bool) {
- if PFUser.currentUser() != nil {
- dismissViewControllerAnimated(true, completion: nil)
- }
- }
-
- override func viewDidLoad() {
- super.viewDidLoad()
-
- // Do any additional setup after loading the view.
- }
-
- @IBAction func loginButtonPressed(sender: AnyObject) {
- println("Login Button Pressed")
- loginButton.animation = "pop"
- loginButton.animate()
-
- var username = usernameTextField.text
- var password = passwordTextField.text
-
- passwordTextField.resignFirstResponder()
-
- view.showHUD(view)
-
- PFUser.logInWithUsernameInBackground(usernameTextField.text, password:passwordTextField.text) {
- (user, error) -> Void in
-
- if user != nil { // Login successfull
- self.dismissViewControllerAnimated(true, completion: nil)
- hudView.removeFromSuperview()
- println("Successful Login")
-
- } else { // Login failed. Try again or SignUp
- let alert = UIAlertView(title: "Dindr",
- message: "\(error!.localizedDescription)",
- delegate: self,
- cancelButtonTitle: "Retry",
- otherButtonTitles: "Sign Up")
- alert.show()
-
- hudView.removeFromSuperview()
- }
- }
-
- }
-
-
-
-
-
- /* MARK - TEXTFIELD DELEGATES */
- func textFieldShouldReturn(textField: UITextField) -> Bool {
- if textField == usernameTextField {
- passwordTextField.becomeFirstResponder()
- }
- if textField == passwordTextField {
- loginButtonPressed(self)
- passwordTextField.resignFirstResponder()
- }
- return true
- }
-
- // TAP TO DISMISS KEYBOARD
- @IBAction func tapToDismissKeyboard(sender: UITapGestureRecognizer) {
- usernameTextField.resignFirstResponder()
- passwordTextField.resignFirstResponder()
- }
-
-
-
-}
-
-let hudView = UIView(frame: CGRectMake(0, 0, 80, 80))
-let indicatorView = UIActivityIndicatorView(frame: CGRectMake(0, 0, 80, 80))
-let spinImage = UIImageView(frame: CGRectMake(0, 0, 80, 80))
-
-
-//extension UIView {
-// func showHUD(view: UIView) {
-// hudView.center = CGPointMake(view.frame.size.width/2, view.frame.size.height/2)
-// hudView.backgroundColor = UIColor.darkGrayColor()
-// hudView.alpha = 0.9
-// hudView.layer.cornerRadius = hudView.bounds.size.width/2
-//
-// indicatorView.center = CGPointMake(hudView.frame.size.width/2, hudView.frame.size.height/2)
-// indicatorView.activityIndicatorViewStyle = UIActivityIndicatorViewStyle.WhiteLarge
-// hudView.addSubview(indicatorView)
-// indicatorView.startAnimating()
-// view.addSubview(hudView)
-// }
-//}
diff --git a/Podfile b/Podfile
new file mode 100644
index 0000000..8675e2f
--- /dev/null
+++ b/Podfile
@@ -0,0 +1,6 @@
+platform :ios, '8.4'
+
+use_frameworks!
+
+pod 'Parse'
+pod 'Spring', :git => 'https://github.com/MengTo/Spring.git', :branch => 'swift2'
diff --git a/Podfile.lock b/Podfile.lock
new file mode 100644
index 0000000..381bd7e
--- /dev/null
+++ b/Podfile.lock
@@ -0,0 +1,26 @@
+PODS:
+ - Bolts/Tasks (1.2.0)
+ - Parse (1.7.5.3):
+ - Bolts/Tasks (>= 1.2.0)
+ - Spring (1.0.3)
+
+DEPENDENCIES:
+ - Parse
+ - Spring (from `https://github.com/MengTo/Spring.git`, branch `swift2`)
+
+EXTERNAL SOURCES:
+ Spring:
+ :branch: swift2
+ :git: https://github.com/MengTo/Spring.git
+
+CHECKOUT OPTIONS:
+ Spring:
+ :commit: 18d5c7b74489de8044e34767f856d1e574f0820e
+ :git: https://github.com/MengTo/Spring.git
+
+SPEC CHECKSUMS:
+ Bolts: d176cb1e0012175589e389a9db49b85e27787576
+ Parse: 373adbb1ad2e34d383542c3b28f678c49ebe4881
+ Spring: 3f02b5dc3308572ef177b3cad0fa7bbc4b0706f7
+
+COCOAPODS: 0.39.0
diff --git a/Pods/Bolts/Bolts/Common/BFCancellationToken.h b/Pods/Bolts/Bolts/Common/BFCancellationToken.h
new file mode 100644
index 0000000..90a20d7
--- /dev/null
+++ b/Pods/Bolts/Bolts/Common/BFCancellationToken.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
+
+#import
+
+#import
+
+/*!
+ A block that will be called when a token is cancelled.
+ */
+typedef void(^BFCancellationBlock)();
+
+/*!
+ The consumer view of a CancellationToken.
+ Propagates notification that operations should be canceled.
+ A BFCancellationToken has methods to inspect whether the token has been cancelled.
+ */
+@interface BFCancellationToken : NSObject
+
+/*!
+ Whether cancellation has been requested for this token source.
+ */
+@property (nonatomic, assign, readonly, getter=isCancellationRequested) BOOL cancellationRequested;
+
+/*!
+ Register a block to be notified when the token is cancelled.
+ If the token is already cancelled the delegate will be notified immediately.
+ */
+- (BFCancellationTokenRegistration *)registerCancellationObserverWithBlock:(BFCancellationBlock)block;
+
+@end
diff --git a/Pods/Bolts/Bolts/Common/BFCancellationToken.m b/Pods/Bolts/Bolts/Common/BFCancellationToken.m
new file mode 100644
index 0000000..0d91795
--- /dev/null
+++ b/Pods/Bolts/Bolts/Common/BFCancellationToken.m
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
+
+#import "BFCancellationToken.h"
+#import "BFCancellationTokenRegistration.h"
+
+@interface BFCancellationToken ()
+
+@property (atomic, assign, getter=isCancellationRequested) BOOL cancellationRequested;
+@property (nonatomic, strong) NSMutableArray *registrations;
+@property (nonatomic, strong) NSObject *lock;
+@property (nonatomic) BOOL disposed;
+
+@end
+
+@interface BFCancellationTokenRegistration (BFCancellationToken)
+
++ (instancetype)registrationWithToken:(BFCancellationToken *)token delegate:(BFCancellationBlock)delegate;
+
+- (void)notifyDelegate;
+
+@end
+
+@implementation BFCancellationToken
+
+#pragma mark - Initializer
+
+- (instancetype)init {
+ if (self = [super init]) {
+ _registrations = [NSMutableArray array];
+ _lock = [NSObject new];
+ }
+ return self;
+}
+
+#pragma mark - Custom Setters/Getters
+
+- (BOOL)isCancellationRequested {
+ @synchronized(self.lock) {
+ [self throwIfDisposed];
+ return _cancellationRequested;
+ }
+}
+
+- (void)cancel {
+ NSArray *registrations;
+ @synchronized(self.lock) {
+ [self throwIfDisposed];
+ if (_cancellationRequested) {
+ return;
+ }
+ [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(cancelPrivate) object:nil];
+ _cancellationRequested = YES;
+ registrations = [self.registrations copy];
+ }
+
+ [self notifyCancellation:registrations];
+}
+
+- (void)notifyCancellation:(NSArray *)registrations {
+ for (BFCancellationTokenRegistration *registration in registrations) {
+ [registration notifyDelegate];
+ }
+}
+
+- (BFCancellationTokenRegistration *)registerCancellationObserverWithBlock:(BFCancellationBlock)block {
+ @synchronized(self.lock) {
+ BFCancellationTokenRegistration *registration = [BFCancellationTokenRegistration registrationWithToken:self delegate:[block copy]];
+ [self.registrations addObject:registration];
+
+ return registration;
+ }
+}
+
+- (void)unregisterRegistration:(BFCancellationTokenRegistration *)registration {
+ @synchronized(self.lock) {
+ [self throwIfDisposed];
+ [self.registrations removeObject:registration];
+ }
+}
+
+// Delay on a non-public method to prevent interference with a user calling performSelector or
+// cancelPreviousPerformRequestsWithTarget on the public method
+- (void)cancelPrivate {
+ [self cancel];
+}
+
+- (void)cancelAfterDelay:(int)millis {
+ [self throwIfDisposed];
+ NSAssert(millis >= -1, @"Delay must be >= -1");
+
+ if (millis == 0) {
+ [self cancel];
+ return;
+ }
+
+ @synchronized(self.lock) {
+ [self throwIfDisposed];
+ [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(cancelPrivate) object:nil];
+ if (self.cancellationRequested) {
+ return;
+ }
+
+ if (millis != -1) {
+ double delay = (double)millis / 1000;
+ [self performSelector:@selector(cancelPrivate) withObject:nil afterDelay:delay];
+ }
+ }
+}
+
+- (void)dispose {
+ @synchronized(self.lock) {
+ if (self.disposed) {
+ return;
+ }
+ self.disposed = YES;
+ for (BFCancellationTokenRegistration *registration in self.registrations) {
+ [registration dispose];
+ }
+ [self.registrations removeAllObjects];
+ }
+}
+
+- (void)throwIfDisposed {
+ NSAssert(!self.disposed, @"Object already disposed");
+}
+
+@end
diff --git a/Pods/Bolts/Bolts/Common/BFCancellationTokenRegistration.h b/Pods/Bolts/Bolts/Common/BFCancellationTokenRegistration.h
new file mode 100644
index 0000000..3e7b711
--- /dev/null
+++ b/Pods/Bolts/Bolts/Common/BFCancellationTokenRegistration.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
+
+#import
+
+/*!
+ Represents the registration of a cancellation observer with a cancellation token.
+ Can be used to unregister the observer at a later time.
+ */
+@interface BFCancellationTokenRegistration : NSObject
+
+/*!
+ Removes the cancellation observer registered with the token
+ and releases all resources associated with this registration.
+ */
+- (void)dispose;
+
+@end
diff --git a/Pods/Bolts/Bolts/Common/BFCancellationTokenRegistration.m b/Pods/Bolts/Bolts/Common/BFCancellationTokenRegistration.m
new file mode 100644
index 0000000..9c8a7ae
--- /dev/null
+++ b/Pods/Bolts/Bolts/Common/BFCancellationTokenRegistration.m
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
+
+#import "BFCancellationTokenRegistration.h"
+
+#import "BFCancellationToken.h"
+
+@interface BFCancellationTokenRegistration ()
+
+@property (nonatomic, weak) BFCancellationToken *token;
+@property (nonatomic, strong) BFCancellationBlock cancellationObserverBlock;
+@property (nonatomic, strong) NSObject *lock;
+@property (nonatomic) BOOL disposed;
+
+@end
+
+@interface BFCancellationToken (BFCancellationTokenRegistration)
+
+- (void)unregisterRegistration:(BFCancellationTokenRegistration *)registration;
+
+@end
+
+@implementation BFCancellationTokenRegistration
+
++ (instancetype)registrationWithToken:(BFCancellationToken *)token delegate:(BFCancellationBlock)delegate {
+ BFCancellationTokenRegistration *registration = [BFCancellationTokenRegistration new];
+ registration.token = token;
+ registration.cancellationObserverBlock = delegate;
+ return registration;
+}
+
+- (instancetype)init {
+ if (self = [super init]) {
+ _lock = [NSObject new];
+ }
+ return self;
+}
+
+- (void)dispose {
+ @synchronized(self.lock) {
+ if (self.disposed) {
+ return;
+ }
+ self.disposed = YES;
+ }
+
+ BFCancellationToken *token = self.token;
+ if (token != nil) {
+ [token unregisterRegistration:self];
+ self.token = nil;
+ }
+ self.cancellationObserverBlock = nil;
+}
+
+- (void)notifyDelegate {
+ @synchronized(self.lock) {
+ [self throwIfDisposed];
+ self.cancellationObserverBlock();
+ }
+}
+
+- (void)throwIfDisposed {
+ NSAssert(!self.disposed, @"Object already disposed");
+}
+
+@end
diff --git a/Pods/Bolts/Bolts/Common/BFCancellationTokenSource.h b/Pods/Bolts/Bolts/Common/BFCancellationTokenSource.h
new file mode 100644
index 0000000..bd6e7a1
--- /dev/null
+++ b/Pods/Bolts/Bolts/Common/BFCancellationTokenSource.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
+
+#import
+
+@class BFCancellationToken;
+
+/*!
+ BFCancellationTokenSource represents the producer side of a CancellationToken.
+ Signals to a CancellationToken that it should be canceled.
+ It is a cancellation token that also has methods
+ for changing the state of a token by cancelling it.
+ */
+@interface BFCancellationTokenSource : NSObject
+
+/*!
+ Creates a new cancellation token source.
+ */
++ (instancetype)cancellationTokenSource;
+
+/*!
+ The cancellation token associated with this CancellationTokenSource.
+ */
+@property (nonatomic, strong, readonly) BFCancellationToken *token;
+
+/*!
+ Whether cancellation has been requested for this token source.
+ */
+@property (nonatomic, assign, readonly, getter=isCancellationRequested) BOOL cancellationRequested;
+
+/*!
+ Cancels the token if it has not already been cancelled.
+ */
+- (void)cancel;
+
+/*!
+ Schedules a cancel operation on this CancellationTokenSource after the specified number of milliseconds.
+ @param millis The number of milliseconds to wait before completing the returned task.
+ If delay is `0` the cancel is executed immediately. If delay is `-1` any scheduled cancellation is stopped.
+ */
+- (void)cancelAfterDelay:(int)millis;
+
+/*!
+ Releases all resources associated with this token source,
+ including disposing of all registrations.
+ */
+- (void)dispose;
+
+@end
diff --git a/Pods/Bolts/Bolts/Common/BFCancellationTokenSource.m b/Pods/Bolts/Bolts/Common/BFCancellationTokenSource.m
new file mode 100644
index 0000000..676b13b
--- /dev/null
+++ b/Pods/Bolts/Bolts/Common/BFCancellationTokenSource.m
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
+
+#import "BFCancellationTokenSource.h"
+
+#import "BFCancellationToken.h"
+
+@interface BFCancellationTokenSource ()
+
+@property (nonatomic, strong, readwrite) BFCancellationToken *token;
+@property (atomic, assign, readwrite, getter=isCancellationRequested) BOOL cancellationRequested;
+@property (atomic, assign) BOOL disposed;
+@property (nonatomic, strong) NSObject *lock;
+
+@end
+
+@interface BFCancellationToken (BFCancellationTokenSource)
+
+- (void)cancel;
+
+- (void)cancelAfterDelay:(int)millis;
+
+- (void)dispose;
+
+- (void)throwIfDisposed;
+
+@end
+
+@implementation BFCancellationTokenSource
+
+#pragma mark - Initializer
+
++ (instancetype)cancellationTokenSource {
+ return [BFCancellationTokenSource new];
+}
+
+- (instancetype)init {
+ if (self = [super init]) {
+ _token = [BFCancellationToken new];
+ _lock = [NSObject new];
+ }
+ return self;
+}
+
+#pragma mark - Custom Setters/Getters
+
+- (BOOL)isCancellationRequested {
+ return _token.isCancellationRequested;
+}
+
+- (void)cancel {
+ [_token cancel];
+}
+
+- (void)cancelAfterDelay:(int)millis {
+ [_token cancelAfterDelay:millis];
+}
+
+- (void)dispose {
+ [_token dispose];
+}
+
+@end
diff --git a/Pods/Bolts/Bolts/Common/BFExecutor.h b/Pods/Bolts/Bolts/Common/BFExecutor.h
new file mode 100644
index 0000000..02af9ba
--- /dev/null
+++ b/Pods/Bolts/Bolts/Common/BFExecutor.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
+
+#import
+
+/*!
+ An object that can run a given block.
+ */
+@interface BFExecutor : NSObject
+
+/*!
+ Returns a default executor, which runs continuations immediately until the call stack gets too
+ deep, then dispatches to a new GCD queue.
+ */
++ (instancetype)defaultExecutor;
+
+/*!
+ Returns an executor that runs continuations on the thread where the previous task was completed.
+ */
++ (instancetype)immediateExecutor;
+
+/*!
+ Returns an executor that runs continuations on the main thread.
+ */
++ (instancetype)mainThreadExecutor;
+
+/*!
+ Returns a new executor that uses the given block to execute continuations.
+ @param block The block to use.
+ */
++ (instancetype)executorWithBlock:(void(^)(void(^block)()))block;
+
+/*!
+ Returns a new executor that runs continuations on the given queue.
+ @param queue The instance of `dispatch_queue_t` to dispatch all continuations onto.
+ */
++ (instancetype)executorWithDispatchQueue:(dispatch_queue_t)queue;
+
+/*!
+ Returns a new executor that runs continuations on the given queue.
+ @param queue The instance of `NSOperationQueue` to run all continuations on.
+ */
++ (instancetype)executorWithOperationQueue:(NSOperationQueue *)queue;
+
+/*!
+ Runs the given block using this executor's particular strategy.
+ @param block The block to execute.
+ */
+- (void)execute:(void(^)())block;
+
+@end
diff --git a/Pods/Bolts/Bolts/Common/BFExecutor.m b/Pods/Bolts/Bolts/Common/BFExecutor.m
new file mode 100644
index 0000000..292e27c
--- /dev/null
+++ b/Pods/Bolts/Bolts/Common/BFExecutor.m
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
+
+#import "BFExecutor.h"
+
+@interface BFExecutor ()
+
+@property (nonatomic, copy) void(^block)(void(^block)());
+
+@end
+
+@implementation BFExecutor
+
+#pragma mark - Executor methods
+
++ (instancetype)defaultExecutor {
+ static BFExecutor *defaultExecutor = NULL;
+ static dispatch_once_t onceToken;
+ dispatch_once(&onceToken, ^{
+ defaultExecutor = [self executorWithBlock:^void(void(^block)()) {
+ static const NSString *BFTaskDepthKey = @"BFTaskDepth";
+ static const int BFTaskDefaultExecutorMaxDepth = 20;
+
+ // We prefer to run everything possible immediately, so that there is callstack information
+ // when debugging. However, we don't want the stack to get too deep, so if the number of
+ // recursive calls to this method exceeds a certain depth, we dispatch to another GCD queue.
+ NSMutableDictionary *threadLocal = [[NSThread currentThread] threadDictionary];
+ NSNumber *depth = threadLocal[BFTaskDepthKey];
+ if (!depth) {
+ depth = @0;
+ }
+ if (depth.intValue > BFTaskDefaultExecutorMaxDepth) {
+ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), block);
+ } else {
+ NSNumber *previousDepth = depth;
+ threadLocal[BFTaskDepthKey] = @(previousDepth.intValue + 1);
+ @try {
+ block();
+ } @finally {
+ threadLocal[BFTaskDepthKey] = previousDepth;
+ }
+ }
+ }];
+ });
+ return defaultExecutor;
+}
+
++ (instancetype)immediateExecutor {
+ static BFExecutor *immediateExecutor = NULL;
+ static dispatch_once_t onceToken;
+ dispatch_once(&onceToken, ^{
+ immediateExecutor = [self executorWithBlock:^void(void(^block)()) {
+ block();
+ }];
+ });
+ return immediateExecutor;
+}
+
++ (instancetype)mainThreadExecutor {
+ static BFExecutor *mainThreadExecutor = NULL;
+ static dispatch_once_t onceToken;
+ dispatch_once(&onceToken, ^{
+ mainThreadExecutor = [self executorWithBlock:^void(void(^block)()) {
+ if (![NSThread isMainThread]) {
+ dispatch_async(dispatch_get_main_queue(), block);
+ } else {
+ block();
+ }
+ }];
+ });
+ return mainThreadExecutor;
+}
+
++ (instancetype)executorWithBlock:(void(^)(void(^block)()))block {
+ return [[self alloc] initWithBlock:block];
+}
+
++ (instancetype)executorWithDispatchQueue:(dispatch_queue_t)queue {
+ return [self executorWithBlock:^void(void(^block)()) {
+ dispatch_async(queue, block);
+ }];
+}
+
++ (instancetype)executorWithOperationQueue:(NSOperationQueue *)queue {
+ return [self executorWithBlock:^void(void(^block)()) {
+ [queue addOperation:[NSBlockOperation blockOperationWithBlock:block]];
+ }];
+}
+
+#pragma mark - Initializer
+
+- (instancetype)initWithBlock:(void(^)(void(^block)()))block {
+ if (self = [super init]) {
+ _block = block;
+ }
+ return self;
+}
+
+#pragma mark - Execution
+
+- (void)execute:(void(^)())block {
+ self.block(block);
+}
+
+@end
diff --git a/Pods/Bolts/Bolts/Common/BFTask.h b/Pods/Bolts/Bolts/Common/BFTask.h
new file mode 100644
index 0000000..dee1137
--- /dev/null
+++ b/Pods/Bolts/Bolts/Common/BFTask.h
@@ -0,0 +1,258 @@
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
+
+#import
+
+#import
+
+/*!
+ Error domain used if there was multiple errors on .
+ */
+extern NSString *const BFTaskErrorDomain;
+
+/*!
+ An exception that is thrown if there was multiple exceptions on .
+ */
+extern NSString *const BFTaskMultipleExceptionsException;
+
+@class BFExecutor;
+@class BFTask;
+
+/*!
+ A block that can act as a continuation for a task.
+ */
+typedef id(^BFContinuationBlock)(BFTask *task);
+
+/*!
+ The consumer view of a Task. A BFTask has methods to
+ inspect the state of the task, and to add continuations to
+ be run once the task is complete.
+ */
+@interface BFTask : NSObject
+
+/*!
+ Creates a task that is already completed with the given result.
+ @param result The result for the task.
+ */
++ (instancetype)taskWithResult:(id)result;
+
+/*!
+ Creates a task that is already completed with the given error.
+ @param error The error for the task.
+ */
++ (instancetype)taskWithError:(NSError *)error;
+
+/*!
+ Creates a task that is already completed with the given exception.
+ @param exception The exception for the task.
+ */
++ (instancetype)taskWithException:(NSException *)exception;
+
+/*!
+ Creates a task that is already cancelled.
+ */
++ (instancetype)cancelledTask;
+
+/*!
+ Returns a task that will be completed (with result == nil) once
+ all of the input tasks have completed.
+ @param tasks An `NSArray` of the tasks to use as an input.
+ */
++ (instancetype)taskForCompletionOfAllTasks:(NSArray *)tasks;
+
+/*!
+ Returns a task that will be completed once all of the input tasks have completed.
+ If all tasks complete successfully without being faulted or cancelled the result will be
+ an `NSArray` of all task results in the order they were provided.
+ @param tasks An `NSArray` of the tasks to use as an input.
+ */
++ (instancetype)taskForCompletionOfAllTasksWithResults:(NSArray *)tasks;
+
+/*!
+ Returns a task that will be completed a certain amount of time in the future.
+ @param millis The approximate number of milliseconds to wait before the
+ task will be finished (with result == nil).
+ */
++ (instancetype)taskWithDelay:(int)millis;
+
+/*!
+ Returns a task that will be completed a certain amount of time in the future.
+ @param millis The approximate number of milliseconds to wait before the
+ task will be finished (with result == nil).
+ @param token The cancellation token (optional).
+ */
++ (instancetype)taskWithDelay:(int)millis
+ cancellationToken:(BFCancellationToken *)token;
+
+/*!
+ Returns a task that will be completed after the given block completes with
+ the specified executor.
+ @param executor A BFExecutor responsible for determining how the
+ continuation block will be run.
+ @param block The block to immediately schedule to run with the given executor.
+ @returns A task that will be completed after block has run.
+ If block returns a BFTask, then the task returned from
+ this method will not be completed until that task is completed.
+ */
++ (instancetype)taskFromExecutor:(BFExecutor *)executor
+ withBlock:(id (^)())block;
+
+// Properties that will be set on the task once it is completed.
+
+/*!
+ The result of a successful task.
+ */
+@property (nonatomic, strong, readonly) id result;
+
+/*!
+ The error of a failed task.
+ */
+@property (nonatomic, strong, readonly) NSError *error;
+
+/*!
+ The exception of a failed task.
+ */
+@property (nonatomic, strong, readonly) NSException *exception;
+
+/*!
+ Whether this task has been cancelled.
+ */
+@property (nonatomic, assign, readonly, getter=isCancelled) BOOL cancelled;
+
+/*!
+ Whether this task has completed due to an error or exception.
+ */
+@property (nonatomic, assign, readonly, getter=isFaulted) BOOL faulted;
+
+/*!
+ Whether this task has completed.
+ */
+@property (nonatomic, assign, readonly, getter=isCompleted) BOOL completed;
+
+/*!
+ Enqueues the given block to be run once this task is complete.
+ This method uses a default execution strategy. The block will be
+ run on the thread where the previous task completes, unless the
+ the stack depth is too deep, in which case it will be run on a
+ dispatch queue with default priority.
+ @param block The block to be run once this task is complete.
+ @returns A task that will be completed after block has run.
+ If block returns a BFTask, then the task returned from
+ this method will not be completed until that task is completed.
+ */
+- (instancetype)continueWithBlock:(BFContinuationBlock)block;
+
+/*!
+ Enqueues the given block to be run once this task is complete.
+ This method uses a default execution strategy. The block will be
+ run on the thread where the previous task completes, unless the
+ the stack depth is too deep, in which case it will be run on a
+ dispatch queue with default priority.
+ @param block The block to be run once this task is complete.
+ @param cancellationToken The cancellation token (optional).
+ @returns A task that will be completed after block has run.
+ If block returns a BFTask, then the task returned from
+ this method will not be completed until that task is completed.
+ */
+- (instancetype)continueWithBlock:(BFContinuationBlock)block
+ cancellationToken:(BFCancellationToken *)cancellationToken;
+
+/*!
+ Enqueues the given block to be run once this task is complete.
+ @param executor A BFExecutor responsible for determining how the
+ continuation block will be run.
+ @param block The block to be run once this task is complete.
+ @returns A task that will be completed after block has run.
+ If block returns a BFTask, then the task returned from
+ this method will not be completed until that task is completed.
+ */
+- (instancetype)continueWithExecutor:(BFExecutor *)executor
+ withBlock:(BFContinuationBlock)block;
+/*!
+ Enqueues the given block to be run once this task is complete.
+ @param executor A BFExecutor responsible for determining how the
+ continuation block will be run.
+ @param block The block to be run once this task is complete.
+ @param cancellationToken The cancellation token (optional).
+ @returns A task that will be completed after block has run.
+ If block returns a BFTask, then the task returned from
+ his method will not be completed until that task is completed.
+ */
+- (instancetype)continueWithExecutor:(BFExecutor *)executor
+ block:(BFContinuationBlock)block
+ cancellationToken:(BFCancellationToken *)cancellationToken;
+
+/*!
+ Identical to continueWithBlock:, except that the block is only run
+ if this task did not produce a cancellation, error, or exception.
+ If it did, then the failure will be propagated to the returned
+ task.
+ @param block The block to be run once this task is complete.
+ @returns A task that will be completed after block has run.
+ If block returns a BFTask, then the task returned from
+ this method will not be completed until that task is completed.
+ */
+- (instancetype)continueWithSuccessBlock:(BFContinuationBlock)block;
+
+/*!
+ Identical to continueWithBlock:, except that the block is only run
+ if this task did not produce a cancellation, error, or exception.
+ If it did, then the failure will be propagated to the returned
+ task.
+ @param block The block to be run once this task is complete.
+ @param cancellationToken The cancellation token (optional).
+ @returns A task that will be completed after block has run.
+ If block returns a BFTask, then the task returned from
+ this method will not be completed until that task is completed.
+ */
+- (instancetype)continueWithSuccessBlock:(BFContinuationBlock)block
+ cancellationToken:(BFCancellationToken *)cancellationToken;
+
+/*!
+ Identical to continueWithExecutor:withBlock:, except that the block
+ is only run if this task did not produce a cancellation, error, or
+ exception. If it did, then the failure will be propagated to the
+ returned task.
+ @param executor A BFExecutor responsible for determining how the
+ continuation block will be run.
+ @param block The block to be run once this task is complete.
+ @returns A task that will be completed after block has run.
+ If block returns a BFTask, then the task returned from
+ this method will not be completed until that task is completed.
+ */
+- (instancetype)continueWithExecutor:(BFExecutor *)executor
+ withSuccessBlock:(BFContinuationBlock)block;
+
+/*!
+ Identical to continueWithExecutor:withBlock:, except that the block
+ is only run if this task did not produce a cancellation, error, or
+ exception. If it did, then the failure will be propagated to the
+ returned task.
+ @param executor A BFExecutor responsible for determining how the
+ continuation block will be run.
+ @param block The block to be run once this task is complete.
+ @param cancellationToken The cancellation token (optional).
+ @returns A task that will be completed after block has run.
+ If block returns a BFTask, then the task returned from
+ this method will not be completed until that task is completed.
+ */
+- (instancetype)continueWithExecutor:(BFExecutor *)executor
+ successBlock:(BFContinuationBlock)block
+ cancellationToken:(BFCancellationToken *)cancellationToken;
+
+/*!
+ Waits until this operation is completed.
+ This method is inefficient and consumes a thread resource while
+ it's running. It should be avoided. This method logs a warning
+ message if it is used on the main thread.
+ */
+- (void)waitUntilFinished;
+
+@end
diff --git a/Pods/Bolts/Bolts/Common/BFTask.m b/Pods/Bolts/Bolts/Common/BFTask.m
new file mode 100644
index 0000000..58f89cf
--- /dev/null
+++ b/Pods/Bolts/Bolts/Common/BFTask.m
@@ -0,0 +1,468 @@
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
+
+#import "BFTask.h"
+
+#import
+
+#import "Bolts.h"
+
+__attribute__ ((noinline)) void warnBlockingOperationOnMainThread() {
+ NSLog(@"Warning: A long-running operation is being executed on the main thread. \n"
+ " Break on warnBlockingOperationOnMainThread() to debug.");
+}
+
+NSString *const BFTaskErrorDomain = @"bolts";
+NSString *const BFTaskMultipleExceptionsException = @"BFMultipleExceptionsException";
+
+@interface BFTask () {
+ id _result;
+ NSError *_error;
+ NSException *_exception;
+}
+
+@property (atomic, assign, readwrite, getter=isCancelled) BOOL cancelled;
+@property (atomic, assign, readwrite, getter=isFaulted) BOOL faulted;
+@property (atomic, assign, readwrite, getter=isCompleted) BOOL completed;
+
+@property (nonatomic, strong) NSObject *lock;
+@property (nonatomic, strong) NSCondition *condition;
+@property (nonatomic, strong) NSMutableArray *callbacks;
+
+@end
+
+@implementation BFTask
+
+#pragma mark - Initializer
+
+- (instancetype)init {
+ if (self = [super init]) {
+ _lock = [[NSObject alloc] init];
+ _condition = [[NSCondition alloc] init];
+ _callbacks = [NSMutableArray array];
+ }
+ return self;
+}
+
+#pragma mark - Task Class methods
+
++ (instancetype)taskWithResult:(id)result {
+ BFTaskCompletionSource *tcs = [BFTaskCompletionSource taskCompletionSource];
+ tcs.result = result;
+ return tcs.task;
+}
+
++ (instancetype)taskWithError:(NSError *)error {
+ BFTaskCompletionSource *tcs = [BFTaskCompletionSource taskCompletionSource];
+ tcs.error = error;
+ return tcs.task;
+}
+
++ (instancetype)taskWithException:(NSException *)exception {
+ BFTaskCompletionSource *tcs = [BFTaskCompletionSource taskCompletionSource];
+ tcs.exception = exception;
+ return tcs.task;
+}
+
++ (instancetype)cancelledTask {
+ BFTaskCompletionSource *tcs = [BFTaskCompletionSource taskCompletionSource];
+ [tcs cancel];
+ return tcs.task;
+}
+
++ (instancetype)taskForCompletionOfAllTasks:(NSArray *)tasks {
+ __block int32_t total = (int32_t)tasks.count;
+ if (total == 0) {
+ return [self taskWithResult:nil];
+ }
+
+ __block int32_t cancelled = 0;
+ NSObject *lock = [[NSObject alloc] init];
+ NSMutableArray *errors = [NSMutableArray array];
+ NSMutableArray *exceptions = [NSMutableArray array];
+
+ BFTaskCompletionSource *tcs = [BFTaskCompletionSource taskCompletionSource];
+ for (BFTask *task in tasks) {
+ [task continueWithBlock:^id(BFTask *task) {
+ if (task.exception) {
+ @synchronized (lock) {
+ [exceptions addObject:task.exception];
+ }
+ } else if (task.error) {
+ @synchronized (lock) {
+ [errors addObject:task.error];
+ }
+ } else if (task.cancelled) {
+ OSAtomicIncrement32(&cancelled);
+ }
+
+ if (OSAtomicDecrement32(&total) == 0) {
+ if (exceptions.count > 0) {
+ if (exceptions.count == 1) {
+ tcs.exception = [exceptions firstObject];
+ } else {
+ NSException *exception =
+ [NSException exceptionWithName:BFTaskMultipleExceptionsException
+ reason:@"There were multiple exceptions."
+ userInfo:@{ @"exceptions": exceptions }];
+ tcs.exception = exception;
+ }
+ } else if (errors.count > 0) {
+ if (errors.count == 1) {
+ tcs.error = [errors firstObject];
+ } else {
+ NSError *error = [NSError errorWithDomain:BFTaskErrorDomain
+ code:kBFMultipleErrorsError
+ userInfo:@{ @"errors": errors }];
+ tcs.error = error;
+ }
+ } else if (cancelled > 0) {
+ [tcs cancel];
+ } else {
+ tcs.result = nil;
+ }
+ }
+ return nil;
+ }];
+ }
+ return tcs.task;
+}
+
++ (instancetype)taskForCompletionOfAllTasksWithResults:(NSArray *)tasks {
+ return [[self taskForCompletionOfAllTasks:tasks] continueWithSuccessBlock:^id(BFTask *task) {
+ return [tasks valueForKey:@"result"];
+ }];
+}
+
++ (instancetype)taskWithDelay:(int)millis {
+ BFTaskCompletionSource *tcs = [BFTaskCompletionSource taskCompletionSource];
+ dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, millis * NSEC_PER_MSEC);
+ dispatch_after(popTime, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
+ tcs.result = nil;
+ });
+ return tcs.task;
+}
+
++ (instancetype)taskWithDelay:(int)millis
+ cancellationToken:(BFCancellationToken *)token {
+ if (token.cancellationRequested) {
+ return [BFTask cancelledTask];
+ }
+
+ BFTaskCompletionSource *tcs = [BFTaskCompletionSource taskCompletionSource];
+ dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, millis * NSEC_PER_MSEC);
+ dispatch_after(popTime, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
+ if (token.cancellationRequested) {
+ [tcs cancel];
+ return;
+ }
+ tcs.result = nil;
+ });
+ return tcs.task;
+}
+
++ (instancetype)taskFromExecutor:(BFExecutor *)executor
+ withBlock:(id (^)())block {
+ return [[self taskWithResult:nil] continueWithExecutor:executor withBlock:block];
+}
+
+#pragma mark - Custom Setters/Getters
+
+- (id)result {
+ @synchronized(self.lock) {
+ return _result;
+ }
+}
+
+- (void)setResult:(id)result {
+ if (![self trySetResult:result]) {
+ [NSException raise:NSInternalInconsistencyException
+ format:@"Cannot set the result on a completed task."];
+ }
+}
+
+- (BOOL)trySetResult:(id)result {
+ @synchronized(self.lock) {
+ if (self.completed) {
+ return NO;
+ }
+ self.completed = YES;
+ _result = result;
+ [self runContinuations];
+ return YES;
+ }
+}
+
+- (NSError *)error {
+ @synchronized(self.lock) {
+ return _error;
+ }
+}
+
+- (void)setError:(NSError *)error {
+ if (![self trySetError:error]) {
+ [NSException raise:NSInternalInconsistencyException
+ format:@"Cannot set the error on a completed task."];
+ }
+}
+
+- (BOOL)trySetError:(NSError *)error {
+ @synchronized(self.lock) {
+ if (self.completed) {
+ return NO;
+ }
+ self.completed = YES;
+ self.faulted = YES;
+ _error = error;
+ [self runContinuations];
+ return YES;
+ }
+}
+
+- (NSException *)exception {
+ @synchronized(self.lock) {
+ return _exception;
+ }
+}
+
+- (void)setException:(NSException *)exception {
+ if (![self trySetException:exception]) {
+ [NSException raise:NSInternalInconsistencyException
+ format:@"Cannot set the exception on a completed task."];
+ }
+}
+
+- (BOOL)trySetException:(NSException *)exception {
+ @synchronized(self.lock) {
+ if (self.completed) {
+ return NO;
+ }
+ self.completed = YES;
+ self.faulted = YES;
+ _exception = exception;
+ [self runContinuations];
+ return YES;
+ }
+}
+
+- (BOOL)isCancelled {
+ @synchronized(self.lock) {
+ return _cancelled;
+ }
+}
+
+- (BOOL)isFaulted {
+ @synchronized(self.lock) {
+ return _faulted;
+ }
+}
+
+- (void)cancel {
+ @synchronized(self.lock) {
+ if (![self trySetCancelled]) {
+ [NSException raise:NSInternalInconsistencyException
+ format:@"Cannot cancel a completed task."];
+ }
+ }
+}
+
+- (BOOL)trySetCancelled {
+ @synchronized(self.lock) {
+ if (self.completed) {
+ return NO;
+ }
+ self.completed = YES;
+ self.cancelled = YES;
+ [self runContinuations];
+ return YES;
+ }
+}
+
+- (BOOL)isCompleted {
+ @synchronized(self.lock) {
+ return _completed;
+ }
+}
+
+- (void)setCompleted {
+ @synchronized(self.lock) {
+ _completed = YES;
+ }
+}
+
+- (void)runContinuations {
+ @synchronized(self.lock) {
+ [self.condition lock];
+ [self.condition broadcast];
+ [self.condition unlock];
+ for (void (^callback)() in self.callbacks) {
+ callback();
+ }
+ [self.callbacks removeAllObjects];
+ }
+}
+
+#pragma mark - Chaining methods
+
+- (instancetype)continueWithExecutor:(BFExecutor *)executor
+ withBlock:(BFContinuationBlock)block {
+ return [self continueWithExecutor:executor block:block cancellationToken:nil];
+}
+
+- (instancetype)continueWithExecutor:(BFExecutor *)executor
+ block:(BFContinuationBlock)block
+ cancellationToken:(BFCancellationToken *)cancellationToken {
+ BFTaskCompletionSource *tcs = [BFTaskCompletionSource taskCompletionSource];
+
+ // Capture all of the state that needs to used when the continuation is complete.
+ void (^wrappedBlock)() = ^() {
+ [executor execute:^{
+ if (cancellationToken.cancellationRequested) {
+ [tcs cancel];
+ return;
+ }
+
+ id result = nil;
+ @try {
+ result = block(self);
+ } @catch (NSException *exception) {
+ tcs.exception = exception;
+ return;
+ }
+
+ if ([result isKindOfClass:[BFTask class]]) {
+
+ id (^setupWithTask) (BFTask *) = ^id(BFTask *task) {
+ if (task.cancelled) {
+ [tcs cancel];
+ } else if (task.exception) {
+ tcs.exception = task.exception;
+ } else if (task.error) {
+ tcs.error = task.error;
+ } else {
+ tcs.result = task.result;
+ }
+ return nil;
+ };
+
+ BFTask *resultTask = (BFTask *)result;
+
+ if (resultTask.completed) {
+ setupWithTask(resultTask);
+ } else {
+ [resultTask continueWithBlock:setupWithTask cancellationToken:cancellationToken];
+ }
+
+ } else {
+ tcs.result = result;
+ }
+ }];
+ };
+
+ BOOL completed;
+ @synchronized(self.lock) {
+ completed = self.completed;
+ if (!completed) {
+ [self.callbacks addObject:[wrappedBlock copy]];
+ }
+ }
+ if (completed) {
+ wrappedBlock();
+ }
+
+ return tcs.task;
+}
+
+- (instancetype)continueWithBlock:(BFContinuationBlock)block {
+ return [self continueWithExecutor:[BFExecutor defaultExecutor] block:block cancellationToken:nil];
+}
+
+- (instancetype)continueWithBlock:(BFContinuationBlock)block
+ cancellationToken:(BFCancellationToken *)cancellationToken {
+ return [self continueWithExecutor:[BFExecutor defaultExecutor] block:block cancellationToken:cancellationToken];
+}
+
+- (instancetype)continueWithExecutor:(BFExecutor *)executor
+ withSuccessBlock:(BFContinuationBlock)block {
+ return [self continueWithExecutor:executor successBlock:block cancellationToken:nil];
+}
+
+- (instancetype)continueWithExecutor:(BFExecutor *)executor
+ successBlock:(BFContinuationBlock)block
+ cancellationToken:(BFCancellationToken *)cancellationToken {
+ if (cancellationToken.cancellationRequested) {
+ return [BFTask cancelledTask];
+ }
+
+ return [self continueWithExecutor:executor block:^id(BFTask *task) {
+ if (task.faulted || task.cancelled) {
+ return task;
+ } else {
+ return block(task);
+ }
+ } cancellationToken:cancellationToken];
+}
+
+- (instancetype)continueWithSuccessBlock:(BFContinuationBlock)block {
+ return [self continueWithExecutor:[BFExecutor defaultExecutor] successBlock:block cancellationToken:nil];
+}
+
+- (instancetype)continueWithSuccessBlock:(BFContinuationBlock)block
+ cancellationToken:(BFCancellationToken *)cancellationToken {
+ return [self continueWithExecutor:[BFExecutor defaultExecutor] successBlock:block cancellationToken:cancellationToken];
+}
+
+#pragma mark - Syncing Task (Avoid it)
+
+- (void)warnOperationOnMainThread {
+ warnBlockingOperationOnMainThread();
+}
+
+- (void)waitUntilFinished {
+ if ([NSThread isMainThread]) {
+ [self warnOperationOnMainThread];
+ }
+
+ @synchronized(self.lock) {
+ if (self.completed) {
+ return;
+ }
+ [self.condition lock];
+ }
+ [self.condition wait];
+ [self.condition unlock];
+}
+
+#pragma mark - NSObject
+
+- (NSString *)description {
+ // Acquire the data from the locked properties
+ BOOL completed;
+ BOOL cancelled;
+ BOOL faulted;
+
+ @synchronized(self.lock) {
+ completed = self.completed;
+ cancelled = self.cancelled;
+ faulted = self.faulted;
+ }
+
+ // Description string includes status information and, if available, the
+ // result since in some ways this is what a promise actually "is".
+ return [NSString stringWithFormat:@"<%@: %p; completed = %@; cancelled = %@; faulted = %@;%@>",
+ NSStringFromClass([self class]),
+ self,
+ completed ? @"YES" : @"NO",
+ cancelled ? @"YES" : @"NO",
+ faulted ? @"YES" : @"NO",
+ completed ? [NSString stringWithFormat:@" result:%@", _result] : @""];
+}
+
+@end
diff --git a/Pods/Bolts/Bolts/Common/BFTaskCompletionSource.h b/Pods/Bolts/Bolts/Common/BFTaskCompletionSource.h
new file mode 100644
index 0000000..be2fbdb
--- /dev/null
+++ b/Pods/Bolts/Bolts/Common/BFTaskCompletionSource.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
+
+#import
+
+@class BFTask;
+
+/*!
+ A BFTaskCompletionSource represents the producer side of tasks.
+ It is a task that also has methods for changing the state of the
+ task by settings its completion values.
+ */
+@interface BFTaskCompletionSource : NSObject
+
+/*!
+ Creates a new unfinished task.
+ */
++ (instancetype)taskCompletionSource;
+
+/*!
+ The task associated with this TaskCompletionSource.
+ */
+@property (nonatomic, strong, readonly) BFTask *task;
+
+/*!
+ Completes the task by setting the result.
+ Attempting to set this for a completed task will raise an exception.
+ @param result The result of the task.
+ */
+- (void)setResult:(id)result;
+
+/*!
+ Completes the task by setting the error.
+ Attempting to set this for a completed task will raise an exception.
+ @param error The error for the task.
+ */
+- (void)setError:(NSError *)error;
+
+/*!
+ Completes the task by setting an exception.
+ Attempting to set this for a completed task will raise an exception.
+ @param exception The exception for the task.
+ */
+- (void)setException:(NSException *)exception;
+
+/*!
+ Completes the task by marking it as cancelled.
+ Attempting to set this for a completed task will raise an exception.
+ */
+- (void)cancel;
+
+/*!
+ Sets the result of the task if it wasn't already completed.
+ @returns whether the new value was set.
+ */
+- (BOOL)trySetResult:(id)result;
+
+/*!
+ Sets the error of the task if it wasn't already completed.
+ @param error The error for the task.
+ @returns whether the new value was set.
+ */
+- (BOOL)trySetError:(NSError *)error;
+
+/*!
+ Sets the exception of the task if it wasn't already completed.
+ @param exception The exception for the task.
+ @returns whether the new value was set.
+ */
+- (BOOL)trySetException:(NSException *)exception;
+
+/*!
+ Sets the cancellation state of the task if it wasn't already completed.
+ @returns whether the new value was set.
+ */
+- (BOOL)trySetCancelled;
+
+@end
diff --git a/Pods/Bolts/Bolts/Common/BFTaskCompletionSource.m b/Pods/Bolts/Bolts/Common/BFTaskCompletionSource.m
new file mode 100644
index 0000000..bd66835
--- /dev/null
+++ b/Pods/Bolts/Bolts/Common/BFTaskCompletionSource.m
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
+
+#import "BFTaskCompletionSource.h"
+
+#import "BFTask.h"
+
+@interface BFTaskCompletionSource ()
+
+@property (nonatomic, strong, readwrite) BFTask *task;
+
+@end
+
+@interface BFTask (BFTaskCompletionSource)
+
+- (void)setResult:(id)result;
+- (void)setError:(NSError *)error;
+- (void)setException:(NSException *)exception;
+- (void)cancel;
+- (BOOL)trySetResult:(id)result;
+- (BOOL)trySetError:(NSError *)error;
+- (BOOL)trySetException:(NSException *)exception;
+- (BOOL)trySetCancelled;
+
+@end
+
+@implementation BFTaskCompletionSource
+
+#pragma mark - Initializer
+
++ (instancetype)taskCompletionSource {
+ return [[self alloc] init];
+}
+
+- (instancetype)init {
+ if (self = [super init]) {
+ _task = [[BFTask alloc] init];
+ }
+ return self;
+}
+
+#pragma mark - Custom Setters/Getters
+
+- (void)setResult:(id)result {
+ [self.task setResult:result];
+}
+
+- (void)setError:(NSError *)error {
+ [self.task setError:error];
+}
+
+- (void)setException:(NSException *)exception {
+ [self.task setException:exception];
+}
+
+- (void)cancel {
+ [self.task cancel];
+}
+
+- (BOOL)trySetResult:(id)result {
+ return [self.task trySetResult:result];
+}
+
+- (BOOL)trySetError:(NSError *)error {
+ return [self.task trySetError:error];
+}
+
+- (BOOL)trySetException:(NSException *)exception {
+ return [self.task trySetException:exception];
+}
+
+- (BOOL)trySetCancelled {
+ return [self.task trySetCancelled];
+}
+
+@end
diff --git a/Pods/Bolts/Bolts/Common/Bolts.h b/Pods/Bolts/Bolts/Common/Bolts.h
new file mode 100644
index 0000000..ca48a16
--- /dev/null
+++ b/Pods/Bolts/Bolts/Common/Bolts.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
+
+#import
+#import
+#import
+#import
+#import
+#import
+#import
+
+#if __has_include() && TARGET_OS_IPHONE
+#import
+#import
+#import
+#import
+#import
+#import
+#import
+#import
+#import
+#endif
+
+/*! @abstract 80175001: There were multiple errors. */
+extern NSInteger const kBFMultipleErrorsError;
+
+@interface Bolts : NSObject
+
+/*!
+ Returns the version of the Bolts Framework as an NSString.
+ @returns The NSString representation of the current version.
+ */
++ (NSString *)version;
+
+@end
diff --git a/Pods/Bolts/Bolts/Common/Bolts.m b/Pods/Bolts/Bolts/Common/Bolts.m
new file mode 100644
index 0000000..9a3e75c
--- /dev/null
+++ b/Pods/Bolts/Bolts/Common/Bolts.m
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ */
+
+#import "Bolts.h"
+
+NSInteger const kBFMultipleErrorsError = 80175001;
+
+@implementation Bolts
+
++ (NSString *)version {
+ return BOLTS_VERSION;
+}
+
+@end
diff --git a/Pods/Bolts/Bolts/Common/BoltsVersion.h b/Pods/Bolts/Bolts/Common/BoltsVersion.h
new file mode 100644
index 0000000..08353c4
--- /dev/null
+++ b/Pods/Bolts/Bolts/Common/BoltsVersion.h
@@ -0,0 +1 @@
+#define BOLTS_VERSION @"1.2.0"
diff --git a/Pods/Bolts/LICENSE b/Pods/Bolts/LICENSE
new file mode 100644
index 0000000..e1a5831
--- /dev/null
+++ b/Pods/Bolts/LICENSE
@@ -0,0 +1,30 @@
+BSD License
+
+For Bolts software
+
+Copyright (c) 2013-present, Facebook, Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ * Neither the name Facebook nor the names of its contributors may be used to
+ endorse or promote products derived from this software without specific
+ prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\ No newline at end of file
diff --git a/Pods/Bolts/Readme.md b/Pods/Bolts/Readme.md
new file mode 100644
index 0000000..b9d7690
--- /dev/null
+++ b/Pods/Bolts/Readme.md
@@ -0,0 +1,682 @@
+Bolts
+============
+[](https://travis-ci.org/BoltsFramework/Bolts-iOS)
+[](https://coveralls.io/r/BoltsFramework/Bolts-iOS)
+[](http://cocoadocs.org/docsets/Bolts/)
+[](http://cocoadocs.org/docsets/Bolts/)
+[](https://github.com/BoltsFramework/Bolts-iOS/blob/master/LICENSE)
+[](https://www.versioneye.com/objective-c/bolts)
+[](https://www.versioneye.com/objective-c/bolts/references)
+
+Bolts is a collection of low-level libraries designed to make developing mobile
+apps easier. Bolts was designed by Parse and Facebook for our own internal use,
+and we have decided to open source these libraries to make them available to
+others. Using these libraries does not require using any Parse services. Nor
+do they require having a Parse or Facebook developer account.
+
+Bolts includes:
+
+* "Tasks", which make organization of complex asynchronous code more manageable. A task is kind of like a JavaScript Promise, but available for iOS and Android.
+* An implementation of the [App Links protocol](http://www.applinks.org), helping you link to content in other apps and handle incoming deep-links.
+
+For more information, see the [Bolts iOS API Reference](http://boltsframework.github.io/docs/ios/).
+
+# Tasks
+
+To build a truly responsive iOS application, you must keep long-running operations off of the UI thread, and be careful to avoid blocking anything the UI thread might be waiting on. This means you will need to execute various operations in the background. To make this easier, we've added a class called `BFTask`. A task represents the result of an asynchronous operation. Typically, a `BFTask` is returned from an asynchronous function and gives the ability to continue processing the result of the task. When a task is returned from a function, it's already begun doing its job. A task is not tied to a particular threading model: it represents the work being done, not where it is executing. Tasks have many advantages over other methods of asynchronous programming, such as callbacks. `BFTask` is not a replacement for `NSOperation` or GCD. In fact, they play well together. But tasks do fill in some gaps that those technologies don't address.
+* `BFTask` takes care of managing dependencies for you. Unlike using `NSOperation` for dependency management, you don't have to declare all dependencies before starting a `BFTask`. For example, imagine you need to save a set of objects and each one may or may not require saving child objects. With an `NSOperation`, you would normally have to create operations for each of the child saves ahead of time. But you don't always know before you start the work whether that's going to be necessary. That can make managing dependencies with `NSOperation` very painful. Even in the best case, you have to create your dependencies before the operations that depend on them, which results in code that appears in a different order than it executes. With `BFTask`, you can decide during your operation's work whether there will be subtasks and return the other task in just those cases.
+* `BFTasks` release their dependencies. `NSOperation` strongly retains its dependencies, so if you have a queue of ordered operations and sequence them using dependencies, you have a leak, because every operation gets retained forever. `BFTasks` release their callbacks as soon as they are run, so everything cleans up after itself. This can reduce memory use, and simplify memory management.
+* `BFTasks` keep track of the state of finished tasks: It tracks whether there was a returned value, the task was cancelled, or if an error occurred. It also has convenience methods for propagating errors. With `NSOperation`, you have to build all of this stuff yourself.
+* `BFTasks` don't depend on any particular threading model. So it's easy to have some tasks perform their work with an operation queue, while others perform work using blocks with GCD. These tasks can depend on each other seamlessly.
+* Performing several tasks in a row will not create nested "pyramid" code as you would get when using only callbacks.
+* `BFTasks` are fully composable, allowing you to perform branching, parallelism, and complex error handling, without the spaghetti code of having many named callbacks.
+* You can arrange task-based code in the order that it executes, rather than having to split your logic across scattered callback functions.
+
+For the examples in this doc, assume there are async versions of some common Parse methods, called `saveAsync:` and `findAsync:` which return a `Task`. In a later section, we'll show how to define these functions yourself.
+
+## The `continueWithBlock` Method
+
+Every `BFTask` has a method named `continueWithBlock:` which takes a continuation block. A continuation is a block that will be executed when the task is complete. You can then inspect the task to check if it was successful and to get its result.
+
+```objective-c
+// Objective-C
+[[self saveAsync:obj] continueWithBlock:^id(BFTask *task) {
+ if (task.isCancelled) {
+ // the save was cancelled.
+ } else if (task.error) {
+ // the save failed.
+ } else {
+ // the object was saved successfully.
+ PFObject *object = task.result;
+ }
+ return nil;
+}];
+```
+
+```swift
+// Swift
+self.saveAsync(obj).continueWithBlock {
+ (task: BFTask!) -> BFTask in
+ if task.isCancelled() {
+ // the save was cancelled.
+ } else if task.error() {
+ // the save failed.
+ } else {
+ // the object was saved successfully.
+ var object = task.result() as PFObject
+ }
+}
+```
+
+BFTasks use Objective-C blocks, so the syntax should be pretty straightforward. Let's look closer at the types involved with an example.
+
+```objective-c
+// Objective-C
+/**
+ * Gets an NSString asynchronously.
+ */
+- (BFTask *)getStringAsync {
+ // Let's suppose getNumberAsync returns a BFTask whose result is an NSNumber.
+ return [[self getNumberAsync] continueWithBlock:^id(BFTask *task) {
+ // This continuation block takes the NSNumber BFTask as input,
+ // and provides an NSString as output.
+
+ NSNumber *number = task.result;
+ return [NSString stringWithFormat:@"%@", number];
+ )];
+}
+```
+
+```swift
+// Swift
+/**
+ * Gets an NSString asynchronously.
+ */
+func getStringAsync() -> BFTask {
+ //Let's suppose getNumberAsync returns a BFTask whose result is an NSNumber.
+ return self.getNumberAsync().continueWithBlock {
+ (task: BFTask!) -> NSString in
+ // This continuation block takes the NSNumber BFTask as input,
+ // and provides an NSString as output.
+
+ let number = task.result() as NSNumber
+ return NSString(format:"%@", number)
+ }
+}
+```
+
+In many cases, you only want to do more work if the previous task was successful, and propagate any errors or cancellations to be dealt with later. To do this, use the `continueWithSuccessBlock:` method instead of `continueWithBlock:`.
+
+```objective-c
+// Objective-C
+[[self saveAsync:obj] continueWithSuccessBlock:^id(BFTask *task) {
+ // the object was saved successfully.
+ return nil;
+}];
+```
+
+```swift
+// Swift
+self.saveAsync(obj).continueWithSuccessBlock {
+ (task: BFTask!) -> AnyObject! in
+ // the object was saved successfully.
+ return nil
+}
+```
+
+## Chaining Tasks Together
+
+BFTasks are a little bit magical, in that they let you chain them without nesting. If you return a BFTask from `continueWithBlock:`, then the task returned by `continueWithBlock:` will not be considered finished until the new task returned from the new continuation block. This lets you perform multiple actions without incurring the pyramid code you would get with callbacks. Likewise, you can return a `BFTask` from `continueWithSuccessBlock:`. So, return a `BFTask` to do more asynchronous work.
+
+```objective-c
+// Objective-C
+PFQuery *query = [PFQuery queryWithClassName:@"Student"];
+[query orderByDescending:@"gpa"];
+[[[[[self findAsync:query] continueWithSuccessBlock:^id(BFTask *task) {
+ NSArray *students = task.result;
+ PFObject *valedictorian = [students objectAtIndex:0];
+ [valedictorian setObject:@YES forKey:@"valedictorian"];
+ return [self saveAsync:valedictorian];
+}] continueWithSuccessBlock:^id(BFTask *task) {
+ PFObject *valedictorian = task.result;
+ return [self findAsync:query];
+}] continueWithSuccessBlock:^id(BFTask *task) {
+ NSArray *students = task.result;
+ PFObject *salutatorian = [students objectAtIndex:1];
+ [salutatorian setObject:@YES forKey:@"salutatorian"];
+ return [self saveAsync:salutatorian];
+}] continueWithSuccessBlock:^id(BFTask *task) {
+ // Everything is done!
+ return nil;
+}];
+```
+
+```swift
+// Swift
+var query = PFQuery(className:"Student")
+query.orderByDescending("gpa")
+findAsync(query).continueWithSuccessBlock {
+ (task: BFTask!) -> BFTask in
+ let students = task.result() as NSArray
+ var valedictorian = students.objectAtIndex(0) as PFObject
+ valedictorian["valedictorian"] = true
+ return self.saveAsync(valedictorian)
+}.continueWithSuccessBlock {
+ (task: BFTask!) -> BFTask in
+ var valedictorian = task.result() as PFObject
+ return self.findAsync(query)
+}.continueWithSuccessBlock {
+ (task: BFTask!) -> BFTask in
+ let students = task.result() as NSArray
+ var salutatorian = students.objectAtIndex(1) as PFObject
+ salutatorian["salutatorian"] = true
+ return self.saveAsync(salutatorian)
+}.continueWithSuccessBlock {
+ (task: BFTask!) -> AnyObject! in
+ // Everything is done!
+ return nil
+}
+```
+
+## Error Handling
+
+By carefully choosing whether to call `continueWithBlock:` or `continueWithSuccessBlock:`, you can control how errors are propagated in your application. Using `continueWithBlock:` lets you handle errors by transforming them or dealing with them. You can think of failed tasks kind of like throwing an exception. In fact, if you throw an exception inside a continuation, the resulting task will be faulted with that exception.
+
+```objective-c
+// Objective-C
+PFQuery *query = [PFQuery queryWithClassName:@"Student"];
+[query orderByDescending:@"gpa"];
+[[[[[self findAsync:query] continueWithSuccessBlock:^id(BFTask *task) {
+ NSArray *students = task.result;
+ PFObject *valedictorian = [students objectAtIndex:0];
+ [valedictorian setObject:@YES forKey:@"valedictorian"];
+ // Force this callback to fail.
+ return [BFTask taskWithError:[NSError errorWithDomain:@"example.com"
+ code:-1
+ userInfo:nil]];
+}] continueWithSuccessBlock:^id(BFTask *task) {
+ // Now this continuation will be skipped.
+ PFQuery *valedictorian = task.result;
+ return [self findAsync:query];
+}] continueWithBlock:^id(BFTask *task) {
+ if (task.error) {
+ // This error handler WILL be called.
+ // The error will be the NSError returned above.
+ // Let's handle the error by returning a new value.
+ // The task will be completed with nil as its value.
+ return nil;
+ }
+ // This will also be skipped.
+ NSArray *students = task.result;
+ PFObject *salutatorian = [students objectAtIndex:1];
+ [salutatorian setObject:@YES forKey:@"salutatorian"];
+ return [self saveAsync:salutatorian];
+}] continueWithSuccessBlock:^id(BFTask *task) {
+ // Everything is done! This gets called.
+ // The task's result is nil.
+ return nil;
+}];
+```
+
+```swift
+// Swift
+var query = PFQuery(className:"Student")
+query.orderByDescending("gpa")
+findAsync(query).continueWithSuccessBlock {
+ (task: BFTask!) -> BFTask in
+ let students = task.result() as NSArray
+ var valedictorian = students.objectAtIndex(0) as PFObject
+ valedictorian["valedictorian"] = true
+ //Force this callback to fail.
+ return BFTask(error:NSError(domain:"example.com",
+ code:-1, userInfo: nil))
+}.continueWithSuccessBlock {
+ (task: BFTask!) -> AnyObject! in
+ //Now this continuation will be skipped.
+ var valedictorian = task.result() as PFObject
+ return self.findAsync(query)
+}.continueWithBlock {
+ (task: BFTask!) -> AnyObject! in
+ if task.error() {
+ // This error handler WILL be called.
+ // The error will be the NSError returned above.
+ // Let's handle the error by returning a new value.
+ // The task will be completed with nil as its value.
+ return nil
+ }
+ // This will also be skipped.
+ let students = task.result() as NSArray
+ var salutatorian = students.objectAtIndex(1) as PFObject
+ salutatorian["salutatorian"] = true
+ return self.saveAsync(salutatorian)
+}.continueWithSuccessBlock {
+ (task: BFTask!) -> AnyObject! in
+ // Everything is done! This gets called.
+ // The tasks result is nil.
+ return nil
+}
+```
+
+It's often convenient to have a long chain of success callbacks with only one error handler at the end.
+
+## Creating Tasks
+
+When you're getting started, you can just use the tasks returned from methods like `findAsync:` or `saveAsync:`. However, for more advanced scenarios, you may want to make your own tasks. To do that, you create a `BFTaskCompletionSource`. This object will let you create a new `BFTask`, and control whether it gets marked as finished or cancelled. After you create a `BFTask`, you'll need to call `setResult:`, `setError:`, or `cancel` to trigger its continuations.
+
+```objective-c
+// Objective-C
+- (BFTask *)successAsync {
+ BFTaskCompletionSource *successful = [BFTaskCompletionSource taskCompletionSource];
+ [successful setResult:@"The good result."];
+ return successful.task;
+}
+
+- (BFTask *)failAsync {
+ BFTaskCompletionSource *failed = [BFTaskCompletionSource taskCompletionSource];
+ [failed setError:[NSError errorWithDomain:@"example.com" code:-1 userInfo:nil]];
+ return failed.task;
+}
+```
+
+```swift
+// Swift
+func successAsync() -> BFTask {
+ var successful = BFTaskCompletionSource()
+ successful.setResult("The good result.")
+ return successful.task
+}
+
+func failAsync() -> BFTask {
+ var failed = BFTaskCompletionSource()
+ failed.setError(NSError(domain:"example.com", code:-1, userInfo:nil))
+ return failed.task
+}
+```
+
+If you know the result of a task at the time it is created, there are some convenience methods you can use.
+
+```objective-c
+// Objective-C
+BFTask *successful = [BFTask taskWithResult:@"The good result."];
+
+BFTask *failed = [BFTask taskWithError:anError];
+```
+
+```swift
+// Swift
+let successful = BFTask(result:"The good result")
+
+let failed = BFTask(error:anError)
+```
+
+## Creating Async Methods
+
+With these tools, it's easy to make your own asynchronous functions that return tasks. For example, you can make a task-based version of `fetchAsync:` easily.
+
+```objective-c
+// Objective-C
+- (BFTask *) fetchAsync:(PFObject *)object {
+ BFTaskCompletionSource *task = [BFTaskCompletionSource taskCompletionSource];
+ [object fetchInBackgroundWithBlock:^(PFObject *object, NSError *error) {
+ if (!error) {
+ [task setResult:object];
+ } else {
+ [task setError:error];
+ }
+ }];
+ return task.task;
+}
+```
+
+```swift
+// Swift
+func fetchAsync(object: PFObject) -> BFTask {
+ var task = BFTaskCompletionSource()
+ object.fetchInBackgroundWithBlock {
+ (object: PFObject!, error: NSError!) -> Void in
+ if error == nil {
+ task.setResult(object)
+ } else {
+ task.setError(error)
+ }
+ }
+ return task.task
+}
+
+```
+
+It's similarly easy to create `saveAsync:`, `findAsync:` or `deleteAsync:`.
+
+## Tasks in Series
+
+`BFTasks` are convenient when you want to do a series of tasks in a row, each one waiting for the previous to finish. For example, imagine you want to delete all of the comments on your blog.
+
+```objective-c
+// Objective-C
+PFQuery *query = [PFQuery queryWithClassName:@"Comments"];
+[query whereKey:@"post" equalTo:@123];
+
+[[[self findAsync:query] continueWithBlock:^id(BFTask *task) {
+ NSArray *results = task.result;
+
+ // Create a trivial completed task as a base case.
+ BFTask *task = [BFTask taskWithResult:nil];
+ for (PFObject *result in results) {
+ // For each item, extend the task with a function to delete the item.
+ task = [task continueWithBlock:^id(BFTask *task) {
+ // Return a task that will be marked as completed when the delete is finished.
+ return [self deleteAsync:result];
+ }];
+ }
+ return task;
+}] continueWithBlock:^id(BFTask *task) {
+ // Every comment was deleted.
+ return nil;
+}];
+```
+
+```swift
+// Swift
+var query = PFQuery(className:"Comments")
+query.whereKey("post", equalTo:123)
+findAsync(query).continueWithBlock {
+ (task: BFTask!) -> BFTask in
+ let results = task.result() as NSArray
+
+ // Create a trivial completed task as a base case.
+ let task = BFTask(result:nil)
+ for result : PFObject in results {
+ // For each item, extend the task with a function to delete the item.
+ task = task.continueWithBlock {
+ (task: BFTask!) -> BFTask in
+ return self.deleteAsync(result)
+ }
+ }
+ return task
+}.continueWithBlock {
+ (task: BFTask!) -> AnyObject! in
+ // Every comment was deleted.
+ return nil
+}
+```
+
+## Tasks in Parallel
+
+You can also perform several tasks in parallel, using the `taskForCompletionOfAllTasks:` method. You can start multiple operations at once, and use `taskForCompletionOfAllTasks:` to create a new task that will be marked as completed when all of its input tasks are completed. The new task will be successful only if all of the passed-in tasks succeed. Performing operations in parallel will be faster than doing them serially, but may consume more system resources and bandwidth.
+
+```objective-c
+// Objective-C
+PFQuery *query = [PFQuery queryWithClassName:@"Comments"];
+[query whereKey:@"post" equalTo:@123];
+
+[[[self findAsync:query] continueWithBlock:^id(BFTask *results) {
+ // Collect one task for each delete into an array.
+ NSMutableArray *tasks = [NSMutableArray array];
+ for (PFObject *result in results) {
+ // Start this delete immediately and add its task to the list.
+ [tasks addObject:[self deleteAsync:result]];
+ }
+ // Return a new task that will be marked as completed when all of the deletes are
+ // finished.
+ return [BFTask taskForCompletionOfAllTasks:tasks];
+}] continueWithBlock:^id(BFTask *task) {
+ // Every comment was deleted.
+ return nil;
+}];
+```
+
+```swift
+// Swift
+var query = PFQuery(className:"Comments")
+query.whereKey("post", equalTo:123)
+
+findAsync(query).continueWithBlock {
+ (task: BFTask!) -> BFTask in
+ // Collect one task for each delete into an array.
+ var tasks = NSMutableArray.array()
+ var results = task.result() as NSArray
+ for result : PFObject! in results {
+ // Start this delete immediately and add its task to the list.
+ tasks.addObject(self.deleteAsync(result))
+ }
+ // Return a new task that will be marked as completed when all of the deletes
+ // are finished.
+ return BFTask(forCompletionOfAllTasks:tasks)
+}.continueWithBlock {
+ (task: BFTask!) -> AnyObject! in
+ // Every comment was deleted.
+ return nil
+}
+```
+
+## Task Executors
+
+Both `continueWithBlock:` and `continueWithSuccessBlock:` methods have another form that takes an instance of `BFExecutor`. These are `continueWithExecutor:withBlock:` and `continueWithExecutor:withSuccessBlock:`. These methods allow you to control how the continuation is executed. The default executor will dispatch to GCD, but you can provide your own executor to schedule work onto a different thread. For example, if you want to continue with work on the UI thread:
+
+```objective-c
+// Create a BFExecutor that uses the main thread.
+BFExecutor *myExecutor = [BFExecutor executorWithBlock:^void(void(^block)()) {
+ dispatch_async(dispatch_get_main_queue(), block);
+}];
+
+// And use the Main Thread Executor like this. The executor applies only to the new
+// continuation being passed into continueWithBlock.
+[[self fetchAsync:object] continueWithExecutor:myExecutor withBlock:^id(BFTask *task) {
+ myTextView.text = [object objectForKey:@"name"];
+}];
+```
+
+For common cases, such as dispatching on the main thread, we have provided default implementations of `BFExecutor`. These include `defaultExecutor`, `immediateExecutor`, `mainThreadExecutor`, `executorWithDispatchQueue:`, and `executorWithOperationQueue:`. For example:
+
+```objective-c
+// Continue on the Main Thread, using a built-in executor.
+[[self fetchAsync:object] continueWithExecutor:[BFExecutor mainThreadExecutor] withBlock:^id(BFTask *task) {
+ myTextView.text = [object objectForKey:@"name"];
+}];
+```
+
+## Task Cancellation
+
+It's generally bad design to keep track of the `BFTaskCompletionSource` for cancellation. A better model is to create a "cancellation token" at the top level, and pass that to each async function that you want to be part of the same "cancelable operation". Then, in your continuation blocks, you can check whether the cancellation token has been cancelled and bail out early by returning a `[BFTask cancelledTask]`. For example:
+
+```objective-c
+- (void)doSomethingComplicatedAsync:(MYCancellationToken *)cancellationToken {
+ [[self doSomethingAsync:cancellationToken] continueWithBlock:^{
+ if (cancellationToken.isCancelled) {
+ return [BFTask cancelledTask];
+ }
+ // Do something that takes a while.
+ return result;
+ }];
+}
+
+// Somewhere else.
+MYCancellationToken *cancellationToken = [[MYCancellationToken alloc] init];
+[obj doSomethingComplicatedAsync:cancellationToken];
+
+// When you get bored...
+[cancellationToken cancel];
+```
+
+**Note:** The cancellation token implementation should be thread-safe.
+We are likely to add some concept like this to Bolts at some point in the future.
+
+# App Links
+
+[App Links](http://www.applinks.org) provide a cross-platform mechanism that allows a developer to define and publish a deep-linking scheme for their content, allowing other apps to link directly to an experience optimized for the device they are running on. Whether you are building an app that receives incoming links or one that may link out to other apps' content, Bolts provides tools to simplify implementation of the [App Links protocol](http://www.applinks.org/documentation).
+
+## Handling an App Link
+
+The most common case will be making your app receive App Links. In-linking will allow your users to quickly access the richest, most native-feeling presentation of linked content on their devices. Bolts makes it easy to handle an inbound App Link (as well as general inbound deep-links) by providing utilities for processing an incoming URL.
+
+For example, you can use the `BFURL` utility class to parse an incoming URL in your `AppDelegate`:
+
+```objective-c
+- (BOOL)application:(UIApplication *)application
+ openURL:(NSURL *)url
+ sourceApplication:(NSString *)sourceApplication
+ annotation:(id)annotation {
+ BFURL *parsedUrl = [BFURL URLWithInboundURL:url sourceApplication:sourceApplication];
+
+ // Use the target URL from the App Link to locate content.
+ if ([parsedUrl.targetURL.pathComponents[1] isEqualToString:@"profiles"]) {
+ // Open a profile viewer.
+ }
+
+ // You can also check the query string easily.
+ NSString *query = parsedUrl.targetQueryParameters[@"query"];
+
+ // Apps that have existing deep-linking support and map their App Links to existing
+ // deep-linking functionality may instead want to perform these operations on the input URL.
+ // Use the target URL from the App Link to locate content.
+ if ([parsedUrl.inputURL.pathComponents[1] isEqualToString:@"profiles"]) {
+ // Open a profile viewer.
+ }
+
+ // You can also check the query string easily.
+ NSString *query = parsedUrl.inputQueryParameters[@"query"];
+
+ // Apps can easily check the Extras and App Link data from the App Link as well.
+ NSString *fbAccessToken = parsedUrl.appLinkExtras[@"fb_access_token"];
+ NSDictionary *refererData = parsedUrl.appLinkExtras[@"referer"];
+}
+```
+
+## Navigating to a URL
+
+Following an App Link allows your app to provide the best user experience (as defined by the receiving app) when a user navigates to a link. Bolts makes this process simple, automating the steps required to follow a link:
+
+1. Resolve the App Link by getting the App Link metadata from the HTML at the URL specified.
+2. Step through App Link targets relevant to the device being used, checking whether the app that can handle the target is present on the device.
+3. If an app is present, build a URL with the appropriate al_applink_data specified and navigate to that URL.
+4. Otherwise, open the browser with the original URL specified.
+
+In the simplest case, it takes just one line of code to navigate to a URL that may have an App Link:
+
+```objective-c
+[BFAppLinkNavigation navigateToURLInBackground:url];
+```
+
+### Adding App and Navigation Data
+
+Under most circumstances, the data that will need to be passed along to an app during a navigation will be contained in the URL itself, so that whether or not the app is actually installed on the device, users are taken to the correct content. Occasionally, however, apps will want to pass along data that is relevant for app-to-app navigation, or will want to augment the App Link protocol with information that might be used by the app to adjust how the app should behave (e.g. showing a link back to the referring app).
+
+If you want to take advantage of these features, you can break apart the navigation process. First, you must have an App Link to which you wish to navigate:
+
+```objective-c
+[[BFAppLinkNavigation resolveAppLinkInBackground:url] continueWithSuccessBlock:^id(BFTask *task) {
+ BFAppLink *link = task.result;
+}];
+```
+
+Then, you can build an App Link request with any additional data you would like and navigate:
+
+```objective-c
+BFAppLinkNavigation *navigation = [BFAppLinkNavigation navigationWithAppLink:link
+ extras:@{ @"access_token": @"t0kEn" }
+ appLinkData:@{ @"ref": @"12345" }];
+NSError *error = nil;
+[navigation navigate:&error];
+```
+
+### Resolving App Link Metadata
+
+Bolts allows for custom App Link resolution, which may be used as a performance optimization (e.g. caching the metadata) or as a mechanism to allow developers to use a centralized index for obtaining App Link metadata. A custom App Link resolver just needs to be able to take a URL and return a `BFAppLink` containing the ordered list of `BFAppLinkTarget`s that are applicable for this device. Bolts provides one of these out of the box that performs this resolution on the device using a hidden UIWebView.
+
+You can use any resolver that implements the `BFAppLinkResolving` protocol by using one of the overloads on `BFAppLinkNavigation`:
+
+```objective-c
+[BFAppLinkNavigation navigateToURLInBackground:url
+ resolver:resolver];
+```
+
+Alternatively, a you can swap out the default resolver to be used by the built-in APIs:
+
+```objective-c
+[BFAppLinkNavigation setDefaultResolver:resolver];
+[BFAppLinkNavigation navigateToURLInBackground:url];
+```
+
+## App Link Return-to-Referer View
+
+When an application is opened via an App Link, a banner allowing the user to "Touch to return to " should be displayed. The `BFAppLinkReturnToRefererView` provides this functionality. It will take an incoming App Link and parse the referer information to display the appropriate calling app name.
+
+```objective-c
+- (void)viewDidLoad {
+ [super viewDidLoad];
+
+ // Perform other view initialization.
+
+ self.returnToRefererController = [[BFAppLinkReturnToRefererController alloc] init];
+
+ // self.returnToRefererView is a BFAppLinkReturnToRefererView.
+ // You may initialize the view either by loading it from a NIB or programmatically.
+ self.returnToRefererController.view = self.returnToRefererView;
+
+ // If you have a UINavigationController in the view, then the bar must be shown above it.
+ [self.returnToRefererController]
+}
+```
+
+The following code assumes that the view controller has an `openedAppLinkURL` `NSURL` property that has already been populated with the URL used to open the app. You can then do something like this to show the view:
+
+```objective-c
+- (void)viewWillAppear {
+ [super viewWillAppear];
+
+ // Show only if you have a back AppLink.
+ [self.returnToRefererController showViewForRefererURL:self.openedAppLinkURL];
+}
+```
+
+In a navigaton-controller view hierarchy, the banner should be displayed above the navigation bar, and `BFAppLinkReturnToRefererController` provides an `initForDisplayAboveNavController` method to assist with this.
+
+## Analytics
+
+Bolts introduces Measurement Event. App Links posts three different Measurement Event notifications to the application, which can be caught and integrated with existing analytics components in your application.
+
+* `al_nav_out` — Raised when your app switches out to an App Links URL.
+* `al_nav_in` — Raised when your app opens an incoming App Links URL.
+* `al_ref_back_out` — Raised when your app returns back the referrer app using the built-in top navigation back bar view.
+
+### Listen for App Links Measurement Events
+
+There are other analytics tools that are integrated with Bolts' App Links events, but you can also listen for these events yourself:
+
+```objective-c
+[[NSNotificationCenter defaultCenter] addObserverForName:BFMeasurementEventNotificationName object:nil queue:nil usingBlock:^(NSNotification *note) {
+ NSDictionary *event = note.userInfo;
+ NSDictionary *eventData = event[BFMeasurementEventArgsKey];
+ // Integrate to your logging/analytics component.
+}];
+```
+
+### App Links Event Fields
+
+App Links Measurement Events sends additional information from App Links Intents in flattened string key value pairs. Here are some of the useful fields for the three events.
+
+* `al_nav_in`
+ * `inputURL`: the URL that opens the app.
+ * `inputURLScheme`: the scheme of `inputURL`.
+ * `refererURL`: the URL that the referrer app added into `al_applink_data`: `referer_app_link`.
+ * `refererAppName`: the app name that the referrer app added to `al_applink_data`: `referer_app_link`.
+ * `sourceApplication`: the bundle of referrer application.
+ * `targetURL`: the `target_url` field in `al_applink_data`.
+ * `version`: App Links API version.
+
+* `al_nav_out` / `al_ref_back_out`
+ * `outputURL`: the URL used to open the other app (or browser). If there is an eligible app to open, this will be the custom scheme url/intent in `al_applink_data`.
+ * `outputURLScheme`: the scheme of `outputURL`.
+ * `sourceURL`: the URL of the page hosting App Links meta tags.
+ * `sourceURLHost`: the hostname of `sourceURL`.
+ * `success`: `“1”` to indicate success in opening the App Link in another app or browser; `“0”` to indicate failure to open the App Link.
+ * `type`: `“app”` for open in app, `“web”` for open in browser; `“fail”` when the success field is `“0”`.
+ * `version`: App Links API version.
+
+# Installation
+
+You can download the latest framework files from our [Releases page](https://github.com/BoltsFramework/Bolts-iOS/releases).
+
+Bolts is also available through [CocoaPods](http://cocoapods.org). To install it simply add the following line to your Podfile:
+
+ pod 'Bolts'
diff --git a/Pods/Headers/Private/Bolts/BFCancellationToken.h b/Pods/Headers/Private/Bolts/BFCancellationToken.h
new file mode 120000
index 0000000..0b69486
--- /dev/null
+++ b/Pods/Headers/Private/Bolts/BFCancellationToken.h
@@ -0,0 +1 @@
+../../../Bolts/Bolts/Common/BFCancellationToken.h
\ No newline at end of file
diff --git a/Pods/Headers/Private/Bolts/BFCancellationTokenRegistration.h b/Pods/Headers/Private/Bolts/BFCancellationTokenRegistration.h
new file mode 120000
index 0000000..c587ca7
--- /dev/null
+++ b/Pods/Headers/Private/Bolts/BFCancellationTokenRegistration.h
@@ -0,0 +1 @@
+../../../Bolts/Bolts/Common/BFCancellationTokenRegistration.h
\ No newline at end of file
diff --git a/Pods/Headers/Private/Bolts/BFCancellationTokenSource.h b/Pods/Headers/Private/Bolts/BFCancellationTokenSource.h
new file mode 120000
index 0000000..d3d5985
--- /dev/null
+++ b/Pods/Headers/Private/Bolts/BFCancellationTokenSource.h
@@ -0,0 +1 @@
+../../../Bolts/Bolts/Common/BFCancellationTokenSource.h
\ No newline at end of file
diff --git a/Pods/Headers/Private/Bolts/BFExecutor.h b/Pods/Headers/Private/Bolts/BFExecutor.h
new file mode 120000
index 0000000..c071e8c
--- /dev/null
+++ b/Pods/Headers/Private/Bolts/BFExecutor.h
@@ -0,0 +1 @@
+../../../Bolts/Bolts/Common/BFExecutor.h
\ No newline at end of file
diff --git a/Pods/Headers/Private/Bolts/BFTask.h b/Pods/Headers/Private/Bolts/BFTask.h
new file mode 120000
index 0000000..5468334
--- /dev/null
+++ b/Pods/Headers/Private/Bolts/BFTask.h
@@ -0,0 +1 @@
+../../../Bolts/Bolts/Common/BFTask.h
\ No newline at end of file
diff --git a/Pods/Headers/Private/Bolts/BFTaskCompletionSource.h b/Pods/Headers/Private/Bolts/BFTaskCompletionSource.h
new file mode 120000
index 0000000..c74760f
--- /dev/null
+++ b/Pods/Headers/Private/Bolts/BFTaskCompletionSource.h
@@ -0,0 +1 @@
+../../../Bolts/Bolts/Common/BFTaskCompletionSource.h
\ No newline at end of file
diff --git a/Pods/Headers/Private/Bolts/Bolts.h b/Pods/Headers/Private/Bolts/Bolts.h
new file mode 120000
index 0000000..146ac6e
--- /dev/null
+++ b/Pods/Headers/Private/Bolts/Bolts.h
@@ -0,0 +1 @@
+../../../Bolts/Bolts/Common/Bolts.h
\ No newline at end of file
diff --git a/Pods/Headers/Private/Bolts/BoltsVersion.h b/Pods/Headers/Private/Bolts/BoltsVersion.h
new file mode 120000
index 0000000..0fa0e2d
--- /dev/null
+++ b/Pods/Headers/Private/Bolts/BoltsVersion.h
@@ -0,0 +1 @@
+../../../Bolts/Bolts/Common/BoltsVersion.h
\ No newline at end of file
diff --git a/Pods/Headers/Private/Parse/PFACL.h b/Pods/Headers/Private/Parse/PFACL.h
new file mode 120000
index 0000000..105fb99
--- /dev/null
+++ b/Pods/Headers/Private/Parse/PFACL.h
@@ -0,0 +1 @@
+../../../Parse/PFACL.h
\ No newline at end of file
diff --git a/Pods/Headers/Private/Parse/PFAnalytics.h b/Pods/Headers/Private/Parse/PFAnalytics.h
new file mode 120000
index 0000000..7619f13
--- /dev/null
+++ b/Pods/Headers/Private/Parse/PFAnalytics.h
@@ -0,0 +1 @@
+../../../Parse/PFAnalytics.h
\ No newline at end of file
diff --git a/Pods/Headers/Private/Parse/PFAnonymousUtils.h b/Pods/Headers/Private/Parse/PFAnonymousUtils.h
new file mode 120000
index 0000000..95113c8
--- /dev/null
+++ b/Pods/Headers/Private/Parse/PFAnonymousUtils.h
@@ -0,0 +1 @@
+../../../Parse/PFAnonymousUtils.h
\ No newline at end of file
diff --git a/Pods/Headers/Private/Parse/PFCloud.h b/Pods/Headers/Private/Parse/PFCloud.h
new file mode 120000
index 0000000..3eb6eb1
--- /dev/null
+++ b/Pods/Headers/Private/Parse/PFCloud.h
@@ -0,0 +1 @@
+../../../Parse/PFCloud.h
\ No newline at end of file
diff --git a/Pods/Headers/Private/Parse/PFConfig.h b/Pods/Headers/Private/Parse/PFConfig.h
new file mode 120000
index 0000000..4a67069
--- /dev/null
+++ b/Pods/Headers/Private/Parse/PFConfig.h
@@ -0,0 +1 @@
+../../../Parse/PFConfig.h
\ No newline at end of file
diff --git a/Pods/Headers/Private/Parse/PFConstants.h b/Pods/Headers/Private/Parse/PFConstants.h
new file mode 120000
index 0000000..709bfb3
--- /dev/null
+++ b/Pods/Headers/Private/Parse/PFConstants.h
@@ -0,0 +1 @@
+../../../Parse/PFConstants.h
\ No newline at end of file
diff --git a/Pods/Headers/Private/Parse/PFFile.h b/Pods/Headers/Private/Parse/PFFile.h
new file mode 120000
index 0000000..0a4d575
--- /dev/null
+++ b/Pods/Headers/Private/Parse/PFFile.h
@@ -0,0 +1 @@
+../../../Parse/PFFile.h
\ No newline at end of file
diff --git a/Pods/Headers/Private/Parse/PFGeoPoint.h b/Pods/Headers/Private/Parse/PFGeoPoint.h
new file mode 120000
index 0000000..e857843
--- /dev/null
+++ b/Pods/Headers/Private/Parse/PFGeoPoint.h
@@ -0,0 +1 @@
+../../../Parse/PFGeoPoint.h
\ No newline at end of file
diff --git a/Pods/Headers/Private/Parse/PFInstallation.h b/Pods/Headers/Private/Parse/PFInstallation.h
new file mode 120000
index 0000000..3c23cc4
--- /dev/null
+++ b/Pods/Headers/Private/Parse/PFInstallation.h
@@ -0,0 +1 @@
+../../../Parse/PFInstallation.h
\ No newline at end of file
diff --git a/Pods/Headers/Private/Parse/PFNetworkActivityIndicatorManager.h b/Pods/Headers/Private/Parse/PFNetworkActivityIndicatorManager.h
new file mode 120000
index 0000000..9fadf46
--- /dev/null
+++ b/Pods/Headers/Private/Parse/PFNetworkActivityIndicatorManager.h
@@ -0,0 +1 @@
+../../../Parse/PFNetworkActivityIndicatorManager.h
\ No newline at end of file
diff --git a/Pods/Headers/Private/Parse/PFNullability.h b/Pods/Headers/Private/Parse/PFNullability.h
new file mode 120000
index 0000000..51688f0
--- /dev/null
+++ b/Pods/Headers/Private/Parse/PFNullability.h
@@ -0,0 +1 @@
+../../../Parse/PFNullability.h
\ No newline at end of file
diff --git a/Pods/Headers/Private/Parse/PFObject+Subclass.h b/Pods/Headers/Private/Parse/PFObject+Subclass.h
new file mode 120000
index 0000000..97e0763
--- /dev/null
+++ b/Pods/Headers/Private/Parse/PFObject+Subclass.h
@@ -0,0 +1 @@
+../../../Parse/PFObject+Subclass.h
\ No newline at end of file
diff --git a/Pods/Headers/Private/Parse/PFObject.h b/Pods/Headers/Private/Parse/PFObject.h
new file mode 120000
index 0000000..8f31704
--- /dev/null
+++ b/Pods/Headers/Private/Parse/PFObject.h
@@ -0,0 +1 @@
+../../../Parse/PFObject.h
\ No newline at end of file
diff --git a/Pods/Headers/Private/Parse/PFProduct.h b/Pods/Headers/Private/Parse/PFProduct.h
new file mode 120000
index 0000000..ae4f7a8
--- /dev/null
+++ b/Pods/Headers/Private/Parse/PFProduct.h
@@ -0,0 +1 @@
+../../../Parse/PFProduct.h
\ No newline at end of file
diff --git a/Pods/Headers/Private/Parse/PFPurchase.h b/Pods/Headers/Private/Parse/PFPurchase.h
new file mode 120000
index 0000000..b0e75ab
--- /dev/null
+++ b/Pods/Headers/Private/Parse/PFPurchase.h
@@ -0,0 +1 @@
+../../../Parse/PFPurchase.h
\ No newline at end of file
diff --git a/Pods/Headers/Private/Parse/PFPush.h b/Pods/Headers/Private/Parse/PFPush.h
new file mode 120000
index 0000000..77373a0
--- /dev/null
+++ b/Pods/Headers/Private/Parse/PFPush.h
@@ -0,0 +1 @@
+../../../Parse/PFPush.h
\ No newline at end of file
diff --git a/Pods/Headers/Private/Parse/PFQuery.h b/Pods/Headers/Private/Parse/PFQuery.h
new file mode 120000
index 0000000..42848d3
--- /dev/null
+++ b/Pods/Headers/Private/Parse/PFQuery.h
@@ -0,0 +1 @@
+../../../Parse/PFQuery.h
\ No newline at end of file
diff --git a/Pods/Headers/Private/Parse/PFRelation.h b/Pods/Headers/Private/Parse/PFRelation.h
new file mode 120000
index 0000000..5dd6563
--- /dev/null
+++ b/Pods/Headers/Private/Parse/PFRelation.h
@@ -0,0 +1 @@
+../../../Parse/PFRelation.h
\ No newline at end of file
diff --git a/Pods/Headers/Private/Parse/PFRole.h b/Pods/Headers/Private/Parse/PFRole.h
new file mode 120000
index 0000000..76f49d3
--- /dev/null
+++ b/Pods/Headers/Private/Parse/PFRole.h
@@ -0,0 +1 @@
+../../../Parse/PFRole.h
\ No newline at end of file
diff --git a/Pods/Headers/Private/Parse/PFSession.h b/Pods/Headers/Private/Parse/PFSession.h
new file mode 120000
index 0000000..77ed683
--- /dev/null
+++ b/Pods/Headers/Private/Parse/PFSession.h
@@ -0,0 +1 @@
+../../../Parse/PFSession.h
\ No newline at end of file
diff --git a/Pods/Headers/Private/Parse/PFSubclassing.h b/Pods/Headers/Private/Parse/PFSubclassing.h
new file mode 120000
index 0000000..f88565c
--- /dev/null
+++ b/Pods/Headers/Private/Parse/PFSubclassing.h
@@ -0,0 +1 @@
+../../../Parse/PFSubclassing.h
\ No newline at end of file
diff --git a/Pods/Headers/Private/Parse/PFTwitterUtils.h b/Pods/Headers/Private/Parse/PFTwitterUtils.h
new file mode 120000
index 0000000..0d76d9e
--- /dev/null
+++ b/Pods/Headers/Private/Parse/PFTwitterUtils.h
@@ -0,0 +1 @@
+../../../Parse/PFTwitterUtils.h
\ No newline at end of file
diff --git a/Pods/Headers/Private/Parse/PFUser.h b/Pods/Headers/Private/Parse/PFUser.h
new file mode 120000
index 0000000..6c1413a
--- /dev/null
+++ b/Pods/Headers/Private/Parse/PFUser.h
@@ -0,0 +1 @@
+../../../Parse/PFUser.h
\ No newline at end of file
diff --git a/Pods/Headers/Private/Parse/PF_Twitter.h b/Pods/Headers/Private/Parse/PF_Twitter.h
new file mode 120000
index 0000000..64e2955
--- /dev/null
+++ b/Pods/Headers/Private/Parse/PF_Twitter.h
@@ -0,0 +1 @@
+../../../Parse/PF_Twitter.h
\ No newline at end of file
diff --git a/Pods/Headers/Private/Parse/Parse.h b/Pods/Headers/Private/Parse/Parse.h
new file mode 120000
index 0000000..2adf7e0
--- /dev/null
+++ b/Pods/Headers/Private/Parse/Parse.h
@@ -0,0 +1 @@
+../../../Parse/Parse.h
\ No newline at end of file
diff --git a/Pods/Local Podspecs/Spring.podspec.json b/Pods/Local Podspecs/Spring.podspec.json
new file mode 100644
index 0000000..51690ce
--- /dev/null
+++ b/Pods/Local Podspecs/Spring.podspec.json
@@ -0,0 +1,23 @@
+{
+ "name": "Spring",
+ "version": "1.0.3",
+ "license": "MIT",
+ "summary": "A library to simplify iOS animations in Swift.",
+ "homepage": "https://github.com/MengTo/Spring",
+ "authors": {
+ "Meng To": "meng@designcode.io"
+ },
+ "source": {
+ "git": "https://github.com/MengTo/Spring.git",
+ "tag": "1.0.3"
+ },
+ "requires_arc": true,
+ "platforms": {
+ "ios": "8.0"
+ },
+ "source_files": "Spring/*.swift",
+ "resources": [
+ "Spring/*.xib",
+ "SpringApp/*.xcassets"
+ ]
+}
diff --git a/Pods/Manifest.lock b/Pods/Manifest.lock
new file mode 100644
index 0000000..381bd7e
--- /dev/null
+++ b/Pods/Manifest.lock
@@ -0,0 +1,26 @@
+PODS:
+ - Bolts/Tasks (1.2.0)
+ - Parse (1.7.5.3):
+ - Bolts/Tasks (>= 1.2.0)
+ - Spring (1.0.3)
+
+DEPENDENCIES:
+ - Parse
+ - Spring (from `https://github.com/MengTo/Spring.git`, branch `swift2`)
+
+EXTERNAL SOURCES:
+ Spring:
+ :branch: swift2
+ :git: https://github.com/MengTo/Spring.git
+
+CHECKOUT OPTIONS:
+ Spring:
+ :commit: 18d5c7b74489de8044e34767f856d1e574f0820e
+ :git: https://github.com/MengTo/Spring.git
+
+SPEC CHECKSUMS:
+ Bolts: d176cb1e0012175589e389a9db49b85e27787576
+ Parse: 373adbb1ad2e34d383542c3b28f678c49ebe4881
+ Spring: 3f02b5dc3308572ef177b3cad0fa7bbc4b0706f7
+
+COCOAPODS: 0.39.0
diff --git a/Pods/Parse/Empty.m b/Pods/Parse/Empty.m
new file mode 100644
index 0000000..e69de29
diff --git a/Pods/Parse/PFACL.h b/Pods/Parse/PFACL.h
new file mode 100644
index 0000000..3582a1e
--- /dev/null
+++ b/Pods/Parse/PFACL.h
@@ -0,0 +1,265 @@
+//
+// PFACL.h
+//
+// Copyright 2011-present Parse Inc. All rights reserved.
+//
+
+#import
+
+#if TARGET_OS_IPHONE
+#import
+#else
+#import
+#endif
+
+PF_ASSUME_NONNULL_BEGIN
+
+@class PFRole;
+@class PFUser;
+
+/*!
+ The `PFACL` class is used to control which users can access or modify a particular object.
+ Each can have its own `PFACL`. You can grant read and write permissions separately to specific users,
+ to groups of users that belong to roles, or you can grant permissions to "the public" so that,
+ for example, any user could read a particular object but only a particular set of users could write to that object.
+ */
+@interface PFACL : NSObject
+
+///--------------------------------------
+/// @name Creating an ACL
+///--------------------------------------
+
+/*!
+ @abstract Creates an ACL with no permissions granted.
+
+ @returns Returns a new `PFACL`.
+ */
++ (PFACL *)ACL;
+
+/*!
+ @abstract Creates an ACL where only the provided user has access.
+
+ @param user The user to assign access.
+ */
++ (PFACL *)ACLWithUser:(PFUser *)user;
+
+///--------------------------------------
+/// @name Controlling Public Access
+///--------------------------------------
+
+/*!
+ @abstract Set whether the public is allowed to read this object.
+
+ @param allowed Whether the public can read this object.
+ */
+- (void)setPublicReadAccess:(BOOL)allowed;
+
+/*!
+ @abstract Gets whether the public is allowed to read this object.
+
+ @returns `YES` if the public read access is enabled, otherwise `NO`.
+ */
+- (BOOL)getPublicReadAccess;
+
+/*!
+ @abstract Set whether the public is allowed to write this object.
+
+ @param allowed Whether the public can write this object.
+ */
+- (void)setPublicWriteAccess:(BOOL)allowed;
+
+/*!
+ @abstract Gets whether the public is allowed to write this object.
+
+ @returns `YES` if the public write access is enabled, otherwise `NO`.
+ */
+- (BOOL)getPublicWriteAccess;
+
+///--------------------------------------
+/// @name Controlling Access Per-User
+///--------------------------------------
+
+/*!
+ @abstract Set whether the given user id is allowed to read this object.
+
+ @param allowed Whether the given user can write this object.
+ @param userId The <[PFObject objectId]> of the user to assign access.
+ */
+- (void)setReadAccess:(BOOL)allowed forUserId:(NSString *)userId;
+
+/*!
+ @abstract Gets whether the given user id is *explicitly* allowed to read this object.
+ Even if this returns `NO`, the user may still be able to access it if returns `YES`
+ or if the user belongs to a role that has access.
+
+ @param userId The <[PFObject objectId]> of the user for which to retrive access.
+
+ @returns `YES` if the user with this `objectId` has *explicit* read access, otherwise `NO`.
+ */
+- (BOOL)getReadAccessForUserId:(NSString *)userId;
+
+/*!
+ @abstract Set whether the given user id is allowed to write this object.
+
+ @param allowed Whether the given user can read this object.
+ @param userId The `objectId` of the user to assign access.
+ */
+- (void)setWriteAccess:(BOOL)allowed forUserId:(NSString *)userId;
+
+/*!
+ @abstract Gets whether the given user id is *explicitly* allowed to write this object.
+ Even if this returns NO, the user may still be able to write it if returns `YES`
+ or if the user belongs to a role that has access.
+
+ @param userId The <[PFObject objectId]> of the user for which to retrive access.
+
+ @returns `YES` if the user with this `objectId` has *explicit* write access, otherwise `NO`.
+ */
+- (BOOL)getWriteAccessForUserId:(NSString *)userId;
+
+/*!
+ @abstract Set whether the given user is allowed to read this object.
+
+ @param allowed Whether the given user can read this object.
+ @param user The user to assign access.
+ */
+- (void)setReadAccess:(BOOL)allowed forUser:(PFUser *)user;
+
+/*!
+ @abstract Gets whether the given user is *explicitly* allowed to read this object.
+ Even if this returns `NO`, the user may still be able to access it if returns `YES`
+ or if the user belongs to a role that has access.
+
+ @param user The user for which to retrive access.
+
+ @returns `YES` if the user has *explicit* read access, otherwise `NO`.
+ */
+- (BOOL)getReadAccessForUser:(PFUser *)user;
+
+/*!
+ @abstract Set whether the given user is allowed to write this object.
+
+ @param allowed Whether the given user can write this object.
+ @param user The user to assign access.
+ */
+- (void)setWriteAccess:(BOOL)allowed forUser:(PFUser *)user;
+
+/*!
+ @abstract Gets whether the given user is *explicitly* allowed to write this object.
+ Even if this returns `NO`, the user may still be able to write it if returns `YES`
+ or if the user belongs to a role that has access.
+
+ @param user The user for which to retrive access.
+
+ @returns `YES` if the user has *explicit* write access, otherwise `NO`.
+ */
+- (BOOL)getWriteAccessForUser:(PFUser *)user;
+
+///--------------------------------------
+/// @name Controlling Access Per-Role
+///--------------------------------------
+
+/*!
+ @abstract Get whether users belonging to the role with the given name are allowed to read this object.
+ Even if this returns `NO`, the role may still be able to read it if a parent role has read access.
+
+ @param name The name of the role.
+
+ @returns `YES` if the role has read access, otherwise `NO`.
+ */
+- (BOOL)getReadAccessForRoleWithName:(NSString *)name;
+
+/*!
+ @abstract Set whether users belonging to the role with the given name are allowed to read this object.
+
+ @param allowed Whether the given role can read this object.
+ @param name The name of the role.
+ */
+- (void)setReadAccess:(BOOL)allowed forRoleWithName:(NSString *)name;
+
+/*!
+ @abstract Get whether users belonging to the role with the given name are allowed to write this object.
+ Even if this returns `NO`, the role may still be able to write it if a parent role has write access.
+
+ @param name The name of the role.
+
+ @returns `YES` if the role has read access, otherwise `NO`.
+ */
+- (BOOL)getWriteAccessForRoleWithName:(NSString *)name;
+
+/*!
+ @abstract Set whether users belonging to the role with the given name are allowed to write this object.
+
+ @param allowed Whether the given role can write this object.
+ @param name The name of the role.
+ */
+- (void)setWriteAccess:(BOOL)allowed forRoleWithName:(NSString *)name;
+
+/*!
+ @abstract Get whether users belonging to the given role are allowed to read this object.
+ Even if this returns `NO`, the role may still be able to read it if a parent role has read access.
+
+ @discussion The role must already be saved on the server and
+ it's data must have been fetched in order to use this method.
+
+ @param role The name of the role.
+
+ @returns `YES` if the role has read access, otherwise `NO`.
+ */
+- (BOOL)getReadAccessForRole:(PFRole *)role;
+
+/*!
+ @abstract Set whether users belonging to the given role are allowed to read this object.
+
+ @discussion The role must already be saved on the server and
+ it's data must have been fetched in order to use this method.
+
+ @param allowed Whether the given role can read this object.
+ @param role The role to assign access.
+ */
+- (void)setReadAccess:(BOOL)allowed forRole:(PFRole *)role;
+
+/*!
+ @abstract Get whether users belonging to the given role are allowed to write this object.
+ Even if this returns `NO`, the role may still be able to write it if a parent role has write access.
+
+ @discussion The role must already be saved on the server and
+ it's data must have been fetched in order to use this method.
+
+ @param role The name of the role.
+
+ @returns `YES` if the role has write access, otherwise `NO`.
+ */
+- (BOOL)getWriteAccessForRole:(PFRole *)role;
+
+/*!
+ @abstract Set whether users belonging to the given role are allowed to write this object.
+
+ @discussion The role must already be saved on the server and
+ it's data must have been fetched in order to use this method.
+
+ @param allowed Whether the given role can write this object.
+ @param role The role to assign access.
+ */
+- (void)setWriteAccess:(BOOL)allowed forRole:(PFRole *)role;
+
+///--------------------------------------
+/// @name Setting Access Defaults
+///--------------------------------------
+
+/*!
+ @abstract Sets a default ACL that will be applied to all instances of when they are created.
+
+ @param acl The ACL to use as a template for all instance of created after this method has been called.
+ This value will be copied and used as a template for the creation of new ACLs, so changes to the
+ instance after this method has been called will not be reflected in new instance of .
+ @param currentUserAccess - If `YES`, the `PFACL` that is applied to newly-created instance of will
+ provide read and write access to the <[PFUser currentUser]> at the time of creation.
+ - If `NO`, the provided `acl` will be used without modification.
+ - If `acl` is `nil`, this value is ignored.
+ */
++ (void)setDefaultACL:(PF_NULLABLE PFACL *)acl withAccessForCurrentUser:(BOOL)currentUserAccess;
+
+@end
+
+PF_ASSUME_NONNULL_END
diff --git a/Pods/Parse/PFAnalytics.h b/Pods/Parse/PFAnalytics.h
new file mode 100644
index 0000000..a883453
--- /dev/null
+++ b/Pods/Parse/PFAnalytics.h
@@ -0,0 +1,167 @@
+//
+// PFAnalytics.h
+//
+// Copyright 2011-present Parse Inc. All rights reserved.
+//
+
+#import
+
+#if TARGET_OS_IPHONE
+#import
+#else
+#import
+#endif
+
+PF_ASSUME_NONNULL_BEGIN
+
+@class BFTask;
+
+/*!
+ `PFAnalytics` provides an interface to Parse's logging and analytics backend.
+
+ Methods will return immediately and cache the request (+ timestamp) to be
+ handled "eventually." That is, the request will be sent immediately if possible
+ or the next time a network connection is available.
+ */
+@interface PFAnalytics : NSObject
+
+///--------------------------------------
+/// @name App-Open / Push Analytics
+///--------------------------------------
+
+/*!
+ @abstract Tracks this application being launched. If this happened as the result of the
+ user opening a push notification, this method sends along information to
+ correlate this open with that push.
+
+ @discussion Pass in `nil` to track a standard "application opened" event.
+
+ @param launchOptions The `NSDictionary` indicating the reason the application was
+ launched, if any. This value can be found as a parameter to various
+ `UIApplicationDelegate` methods, and can be empty or `nil`.
+
+ @returns Returns the task encapsulating the work being done.
+ */
++ (BFTask *)trackAppOpenedWithLaunchOptions:(PF_NULLABLE NSDictionary *)launchOptions;
+
+/*!
+ @abstract Tracks this application being launched.
+ If this happened as the result of the user opening a push notification,
+ this method sends along information to correlate this open with that push.
+
+ @discussion Pass in `nil` to track a standard "application opened" event.
+
+ @param launchOptions The dictionary indicating the reason the application was
+ launched, if any. This value can be found as a parameter to various
+ `UIApplicationDelegate` methods, and can be empty or `nil`.
+ @param block The block to execute on server response.
+ It should have the following argument signature: `^(BOOL succeeded, NSError *error)`
+ */
++ (void)trackAppOpenedWithLaunchOptionsInBackground:(PF_NULLABLE NSDictionary *)launchOptions
+ block:(PF_NULLABLE PFBooleanResultBlock)block;
+
+/*!
+ @abstract Tracks this application being launched. If this happened as the result of the
+ user opening a push notification, this method sends along information to
+ correlate this open with that push.
+
+ @param userInfo The Remote Notification payload, if any. This value can be
+ found either under `UIApplicationLaunchOptionsRemoteNotificationKey` on `launchOptions`,
+ or as a parameter to `application:didReceiveRemoteNotification:`.
+ This can be empty or `nil`.
+
+ @returns Returns the task encapsulating the work being done.
+ */
++ (BFTask *)trackAppOpenedWithRemoteNotificationPayload:(PF_NULLABLE NSDictionary *)userInfo;
+
+/*!
+ @abstract Tracks this application being launched. If this happened as the result of the
+ user opening a push notification, this method sends along information to
+ correlate this open with that push.
+
+ @param userInfo The Remote Notification payload, if any. This value can be
+ found either under `UIApplicationLaunchOptionsRemoteNotificationKey` on `launchOptions`,
+ or as a parameter to `application:didReceiveRemoteNotification:`. This can be empty or `nil`.
+ @param block The block to execute on server response.
+ It should have the following argument signature: `^(BOOL succeeded, NSError *error)`
+ */
++ (void)trackAppOpenedWithRemoteNotificationPayloadInBackground:(PF_NULLABLE NSDictionary *)userInfo
+ block:(PF_NULLABLE PFBooleanResultBlock)block;
+
+///--------------------------------------
+/// @name Custom Analytics
+///--------------------------------------
+
+/*!
+ @abstract Tracks the occurrence of a custom event.
+
+ @discussion Parse will store a data point at the time of invocation with the given event name.
+
+ @param name The name of the custom event to report to Parse as having happened.
+
+ @returns Returns the task encapsulating the work being done.
+ */
++ (BFTask *)trackEvent:(NSString *)name;
+
+/*!
+ @abstract Tracks the occurrence of a custom event. Parse will store a data point at the
+ time of invocation with the given event name. The event will be sent at some
+ unspecified time in the future, even if Parse is currently inaccessible.
+
+ @param name The name of the custom event to report to Parse as having happened.
+ @param block The block to execute on server response.
+ It should have the following argument signature: `^(BOOL succeeded, NSError *error)`
+ */
++ (void)trackEventInBackground:(NSString *)name block:(PF_NULLABLE PFBooleanResultBlock)block;
+
+/*!
+ @abstract Tracks the occurrence of a custom event with additional dimensions. Parse will
+ store a data point at the time of invocation with the given event name.
+
+ @discussion Dimensions will allow segmentation of the occurrences of this custom event.
+ Keys and values should be NSStrings, and will throw otherwise.
+
+ To track a user signup along with additional metadata, consider the following:
+
+ NSDictionary *dimensions = @{ @"gender": @"m",
+ @"source": @"web",
+ @"dayType": @"weekend" };
+ [PFAnalytics trackEvent:@"signup" dimensions:dimensions];
+
+ @warning There is a default limit of 8 dimensions per event tracked.
+
+ @param name The name of the custom event to report to Parse as having happened.
+ @param dimensions The `NSDictionary` of information by which to segment this event.
+
+ @returns Returns the task encapsulating the work being done.
+ */
++ (BFTask *)trackEvent:(NSString *)name dimensions:(PF_NULLABLE NSDictionary *)dimensions;
+
+/*!
+ @abstract Tracks the occurrence of a custom event with additional dimensions. Parse will
+ store a data point at the time of invocation with the given event name. The
+ event will be sent at some unspecified time in the future, even if Parse is currently inaccessible.
+
+ @discussionDimensions will allow segmentation of the occurrences of this custom event.
+ Keys and values should be NSStrings, and will throw otherwise.
+
+ To track a user signup along with additional metadata, consider the following:
+ NSDictionary *dimensions = @{ @"gender": @"m",
+ @"source": @"web",
+ @"dayType": @"weekend" };
+ [PFAnalytics trackEvent:@"signup" dimensions:dimensions];
+
+ There is a default limit of 8 dimensions per event tracked.
+
+ @param name The name of the custom event to report to Parse as having happened.
+ @param dimensions The `NSDictionary` of information by which to segment this event.
+ @param block The block to execute on server response.
+ It should have the following argument signature: `^(BOOL succeeded, NSError *error)`
+ */
++ (void)trackEventInBackground:(NSString *)name
+ dimensions:(PF_NULLABLE NSDictionary *)dimensions
+ block:(PF_NULLABLE PFBooleanResultBlock)block;
+
+@end
+
+PF_ASSUME_NONNULL_END
diff --git a/Pods/Parse/PFAnonymousUtils.h b/Pods/Parse/PFAnonymousUtils.h
new file mode 100644
index 0000000..7a55591
--- /dev/null
+++ b/Pods/Parse/PFAnonymousUtils.h
@@ -0,0 +1,82 @@
+//
+// PFAnonymousUtils.h
+//
+// Copyright 2011-present Parse Inc. All rights reserved.
+//
+
+#import
+
+#if TARGET_OS_IPHONE
+#import
+#import
+#else
+#import
+#import
+#endif
+
+PF_ASSUME_NONNULL_BEGIN
+
+/*!
+ Provides utility functions for working with Anonymously logged-in users.
+ Anonymous users have some unique characteristics:
+
+ - Anonymous users don't need a user name or password.
+ - Once logged out, an anonymous user cannot be recovered.
+ - When the current user is anonymous, the following methods can be used to switch
+ to a different user or convert the anonymous user into a regular one:
+ - signUp converts an anonymous user to a standard user with the given username and password.
+ Data associated with the anonymous user is retained.
+ - logIn switches users without converting the anonymous user.
+ Data associated with the anonymous user will be lost.
+ - Service logIn (e.g. Facebook, Twitter) will attempt to convert
+ the anonymous user into a standard user by linking it to the service.
+ If a user already exists that is linked to the service, it will instead switch to the existing user.
+ - Service linking (e.g. Facebook, Twitter) will convert the anonymous user
+ into a standard user by linking it to the service.
+ */
+@interface PFAnonymousUtils : NSObject
+
+///--------------------------------------
+/// @name Creating an Anonymous User
+///--------------------------------------
+
+/*!
+ @abstract Creates an anonymous user asynchronously and sets as a result to `BFTask`.
+
+ @returns The task, that encapsulates the work being done.
+ */
++ (BFTask *)logInInBackground;
+
+/*!
+ @abstract Creates an anonymous user.
+
+ @param block The block to execute when anonymous user creation is complete.
+ It should have the following argument signature: `^(PFUser *user, NSError *error)`.
+ */
++ (void)logInWithBlock:(PF_NULLABLE PFUserResultBlock)block;
+
+/*
+ @abstract Creates an anonymous user.
+
+ @param target Target object for the selector.
+ @param selector The selector that will be called when the asynchronous request is complete.
+ It should have the following signature: `(void)callbackWithUser:(PFUser *)user error:(NSError *)error`.
+ */
++ (void)logInWithTarget:(PF_NULLABLE_S id)target selector:(PF_NULLABLE_S SEL)selector;
+
+///--------------------------------------
+/// @name Determining Whether a User is Anonymous
+///--------------------------------------
+
+/*!
+ @abstract Whether the object is logged in anonymously.
+
+ @param user object to check for anonymity. The user must be logged in on this device.
+
+ @returns `YES` if the user is anonymous. `NO` if the user is not the current user or is not anonymous.
+ */
++ (BOOL)isLinkedWithUser:(PF_NULLABLE PFUser *)user;
+
+@end
+
+PF_ASSUME_NONNULL_END
diff --git a/Pods/Parse/PFCloud.h b/Pods/Parse/PFCloud.h
new file mode 100644
index 0000000..f141ade
--- /dev/null
+++ b/Pods/Parse/PFCloud.h
@@ -0,0 +1,91 @@
+//
+// PFCloud.h
+//
+// Copyright 2011-present Parse Inc. All rights reserved.
+//
+
+#import
+
+#if TARGET_OS_IPHONE
+#import
+#else
+#import
+#endif
+
+PF_ASSUME_NONNULL_BEGIN
+
+@class BFTask;
+
+/*!
+ The `PFCloud` class provides methods for interacting with Parse Cloud Functions.
+ */
+@interface PFCloud : NSObject
+
+/*!
+ @abstract Calls the given cloud function *synchronously* with the parameters provided.
+
+ @param function The function name to call.
+ @param parameters The parameters to send to the function.
+
+ @returns The response from the cloud function.
+ */
++ (PF_NULLABLE_S id)callFunction:(NSString *)function withParameters:(PF_NULLABLE NSDictionary *)parameters;
+
+/*!
+ @abstract Calls the given cloud function *synchronously* with the parameters provided and
+ sets the error if there is one.
+
+ @param function The function name to call.
+ @param parameters The parameters to send to the function.
+ @param error Pointer to an `NSError` that will be set if necessary.
+
+ @returns The response from the cloud function.
+ This result could be a `NSDictionary`, an `NSArray`, `NSNumber` or `NSString`.
+ */
++ (PF_NULLABLE_S id)callFunction:(NSString *)function
+ withParameters:(PF_NULLABLE NSDictionary *)parameters
+ error:(NSError **)error;
+
+/*!
+ @abstract Calls the given cloud function *asynchronously* with the parameters provided.
+
+ @param function The function name to call.
+ @param parameters The parameters to send to the function.
+
+ @returns The task, that encapsulates the work being done.
+ */
++ (BFTask *)callFunctionInBackground:(NSString *)function
+ withParameters:(PF_NULLABLE NSDictionary *)parameters;
+
+/*!
+ @abstract Calls the given cloud function *asynchronously* with the parameters provided
+ and executes the given block when it is done.
+
+ @param function The function name to call.
+ @param parameters The parameters to send to the function.
+ @param block The block to execute when the function call finished.
+ It should have the following argument signature: `^(id result, NSError *error)`.
+ */
++ (void)callFunctionInBackground:(NSString *)function
+ withParameters:(PF_NULLABLE NSDictionary *)parameters
+ block:(PF_NULLABLE PFIdResultBlock)block;
+
+/*
+ @abstract Calls the given cloud function *asynchronously* with the parameters provided
+ and then executes the given selector when it is done.
+
+ @param function The function name to call.
+ @param parameters The parameters to send to the function.
+ @param target The object to call the selector on.
+ @param selector The selector to call when the function call finished.
+ It should have the following signature: `(void)callbackWithResult:(id)result error:(NSError *)error`.
+ Result will be `nil` if error is set and vice versa.
+ */
++ (void)callFunctionInBackground:(NSString *)function
+ withParameters:(PF_NULLABLE NSDictionary *)parameters
+ target:(PF_NULLABLE_S id)target
+ selector:(PF_NULLABLE_S SEL)selector;
+
+@end
+
+PF_ASSUME_NONNULL_END
diff --git a/Pods/Parse/PFConfig.h b/Pods/Parse/PFConfig.h
new file mode 100644
index 0000000..5eff195
--- /dev/null
+++ b/Pods/Parse/PFConfig.h
@@ -0,0 +1,105 @@
+//
+// PFConfig.h
+//
+// Copyright 2011-present Parse Inc. All rights reserved.
+//
+
+#import
+
+#if TARGET_OS_IPHONE
+#import
+#else
+#import
+#endif
+
+PF_ASSUME_NONNULL_BEGIN
+
+@class BFTask;
+@class PFConfig;
+
+typedef void(^PFConfigResultBlock)(PFConfig *PF_NULLABLE_S config, NSError *PF_NULLABLE_S error);
+
+/*!
+ `PFConfig` is a representation of the remote configuration object.
+ It enables you to add things like feature gating, a/b testing or simple "Message of the day".
+ */
+@interface PFConfig : NSObject
+
+///--------------------------------------
+/// @name Current Config
+///--------------------------------------
+
+/*!
+ @abstract Returns the most recently fetched config.
+
+ @discussion If there was no config fetched - this method will return an empty instance of `PFConfig`.
+
+ @returns Current, last fetched instance of PFConfig.
+ */
++ (PFConfig *)currentConfig;
+
+///--------------------------------------
+/// @name Retrieving Config
+///--------------------------------------
+
+/*!
+ @abstract Gets the `PFConfig` object *synchronously* from the server.
+
+ @returns Instance of `PFConfig` if the operation succeeded, otherwise `nil`.
+ */
++ (PF_NULLABLE PFConfig *)getConfig;
+
+/*!
+ @abstract Gets the `PFConfig` object *synchronously* from the server and sets an error if it occurs.
+
+ @param error Pointer to an `NSError` that will be set if necessary.
+
+ @returns Instance of PFConfig if the operation succeeded, otherwise `nil`.
+ */
++ (PF_NULLABLE PFConfig *)getConfig:(NSError **)error;
+
+/*!
+ @abstract Gets the `PFConfig` *asynchronously* and sets it as a result of a task.
+
+ @returns The task, that encapsulates the work being done.
+ */
++ (BFTask *)getConfigInBackground;
+
+/*!
+ @abstract Gets the `PFConfig` *asynchronously* and executes the given callback block.
+
+ @param block The block to execute.
+ It should have the following argument signature: `^(PFConfig *config, NSError *error)`.
+ */
++ (void)getConfigInBackgroundWithBlock:(PF_NULLABLE PFConfigResultBlock)block;
+
+///--------------------------------------
+/// @name Parameters
+///--------------------------------------
+
+/*!
+ @abstract Returns the object associated with a given key.
+
+ @param key The key for which to return the corresponding configuration value.
+
+ @returns The value associated with `key`, or `nil` if there is no such value.
+ */
+- (PF_NULLABLE_S id)objectForKey:(NSString *)key;
+
+/*!
+ @abstract Returns the object associated with a given key.
+
+ @discussion This method enables usage of literal syntax on `PFConfig`.
+ E.g. `NSString *value = config[@"key"];`
+
+ @see objectForKey:
+
+ @param keyedSubscript The keyed subscript for which to return the corresponding configuration value.
+
+ @returns The value associated with `key`, or `nil` if there is no such value.
+ */
+- (PF_NULLABLE_S id)objectForKeyedSubscript:(NSString *)keyedSubscript;
+
+@end
+
+PF_ASSUME_NONNULL_END
diff --git a/Pods/Parse/PFConstants.h b/Pods/Parse/PFConstants.h
new file mode 100644
index 0000000..eaac836
--- /dev/null
+++ b/Pods/Parse/PFConstants.h
@@ -0,0 +1,423 @@
+// PFConstants.h
+// Copyright 2011 Parse, Inc. All rights reserved.
+
+#import
+
+#if TARGET_OS_IPHONE
+#import
+#else
+#import
+#endif
+
+@class PFObject;
+@class PFUser;
+
+///--------------------------------------
+/// @name Version
+///--------------------------------------
+
+#define PARSE_VERSION @"1.7.5"
+
+extern NSInteger const PARSE_API_VERSION;
+
+///--------------------------------------
+/// @name Platform
+///--------------------------------------
+
+#define PARSE_IOS_ONLY (TARGET_OS_IPHONE)
+#define PARSE_OSX_ONLY (TARGET_OS_MAC && !(TARGET_OS_IPHONE))
+
+extern NSString *const PF_NONNULL_S kPFDeviceType;
+
+#if PARSE_IOS_ONLY
+#import
+#else
+#import
+@compatibility_alias UIImage NSImage;
+@compatibility_alias UIColor NSColor;
+@compatibility_alias UIView NSView;
+#endif
+
+///--------------------------------------
+/// @name Server
+///--------------------------------------
+
+extern NSString *const PF_NONNULL_S kPFParseServer;
+
+///--------------------------------------
+/// @name Cache Policies
+///--------------------------------------
+
+/*!
+ `PFCachePolicy` specifies different caching policies that could be used with .
+
+ This lets you show data when the user's device is offline,
+ or when the app has just started and network requests have not yet had time to complete.
+ Parse takes care of automatically flushing the cache when it takes up too much space.
+
+ @warning Cache policy could only be set when Local Datastore is not enabled.
+
+ @see PFQuery
+ */
+typedef NS_ENUM(uint8_t, PFCachePolicy) {
+ /*!
+ @abstract The query does not load from the cache or save results to the cache.
+ This is the default cache policy.
+ */
+ kPFCachePolicyIgnoreCache = 0,
+ /*!
+ @abstract The query only loads from the cache, ignoring the network.
+ If there are no cached results, this causes a `NSError` with `kPFErrorCacheMiss` code.
+ */
+ kPFCachePolicyCacheOnly,
+ /*!
+ @abstract The query does not load from the cache, but it will save results to the cache.
+ */
+ kPFCachePolicyNetworkOnly,
+ /*!
+ @abstract The query first tries to load from the cache, but if that fails, it loads results from the network.
+ If there are no cached results, this causes a `NSError` with `kPFErrorCacheMiss` code.
+ */
+ kPFCachePolicyCacheElseNetwork,
+ /*!
+ @abstract The query first tries to load from the network, but if that fails, it loads results from the cache.
+ If there are no cached results, this causes a `NSError` with `kPFErrorCacheMiss` code.
+ */
+ kPFCachePolicyNetworkElseCache,
+ /*!
+ @abstract The query first loads from the cache, then loads from the network.
+ The callback will be called twice - first with the cached results, then with the network results.
+ Since it returns two results at different times, this cache policy cannot be used with synchronous or task methods.
+ */
+ kPFCachePolicyCacheThenNetwork
+};
+
+///--------------------------------------
+/// @name Logging Levels
+///--------------------------------------
+
+/*!
+ `PFLogLevel` enum specifies different levels of logging that could be used to limit or display more messages in logs.
+
+ @see [Parse setLogLevel:]
+ @see [Parse logLevel]
+ */
+typedef NS_ENUM(uint8_t, PFLogLevel) {
+ /*!
+ Log level that disables all logging.
+ */
+ PFLogLevelNone = 0,
+ /*!
+ Log level that if set is going to output error messages to the log.
+ */
+ PFLogLevelError = 1,
+ /*!
+ Log level that if set is going to output the following messages to log:
+ - Errors
+ - Warnings
+ */
+ PFLogLevelWarning = 2,
+ /*!
+ Log level that if set is going to output the following messages to log:
+ - Errors
+ - Warnings
+ - Informational messages
+ */
+ PFLogLevelInfo = 3,
+ /*!
+ Log level that if set is going to output the following messages to log:
+ - Errors
+ - Warnings
+ - Informational messages
+ - Debug messages
+ */
+ PFLogLevelDebug = 4
+};
+
+///--------------------------------------
+/// @name Errors
+///--------------------------------------
+
+extern NSString *const PF_NONNULL_S PFParseErrorDomain;
+
+/*!
+ `PFErrorCode` enum contains all custom error codes that are used as `code` for `NSError` for callbacks on all classes.
+
+ These codes are used when `domain` of `NSError` that you receive is set to `PFParseErrorDomain`.
+ */
+typedef NS_ENUM(NSInteger, PFErrorCode) {
+ /*!
+ @abstract Internal server error. No information available.
+ */
+ kPFErrorInternalServer = 1,
+ /*!
+ @abstract The connection to the Parse servers failed.
+ */
+ kPFErrorConnectionFailed = 100,
+ /*!
+ @abstract Object doesn't exist, or has an incorrect password.
+ */
+ kPFErrorObjectNotFound = 101,
+ /*!
+ @abstract You tried to find values matching a datatype that doesn't
+ support exact database matching, like an array or a dictionary.
+ */
+ kPFErrorInvalidQuery = 102,
+ /*!
+ @abstract Missing or invalid classname. Classnames are case-sensitive.
+ They must start with a letter, and `a-zA-Z0-9_` are the only valid characters.
+ */
+ kPFErrorInvalidClassName = 103,
+ /*!
+ @abstract Missing object id.
+ */
+ kPFErrorMissingObjectId = 104,
+ /*!
+ @abstract Invalid key name. Keys are case-sensitive.
+ They must start with a letter, and `a-zA-Z0-9_` are the only valid characters.
+ */
+ kPFErrorInvalidKeyName = 105,
+ /*!
+ @abstract Malformed pointer. Pointers must be arrays of a classname and an object id.
+ */
+ kPFErrorInvalidPointer = 106,
+ /*!
+ @abstract Malformed json object. A json dictionary is expected.
+ */
+ kPFErrorInvalidJSON = 107,
+ /*!
+ @abstract Tried to access a feature only available internally.
+ */
+ kPFErrorCommandUnavailable = 108,
+ /*!
+ @abstract Field set to incorrect type.
+ */
+ kPFErrorIncorrectType = 111,
+ /*!
+ @abstract Invalid channel name. A channel name is either an empty string (the broadcast channel)
+ or contains only `a-zA-Z0-9_` characters and starts with a letter.
+ */
+ kPFErrorInvalidChannelName = 112,
+ /*!
+ @abstract Invalid device token.
+ */
+ kPFErrorInvalidDeviceToken = 114,
+ /*!
+ @abstract Push is misconfigured. See details to find out how.
+ */
+ kPFErrorPushMisconfigured = 115,
+ /*!
+ @abstract The object is too large.
+ */
+ kPFErrorObjectTooLarge = 116,
+ /*!
+ @abstract That operation isn't allowed for clients.
+ */
+ kPFErrorOperationForbidden = 119,
+ /*!
+ @abstract The results were not found in the cache.
+ */
+ kPFErrorCacheMiss = 120,
+ /*!
+ @abstract Keys in `NSDictionary` values may not include `$` or `.`.
+ */
+ kPFErrorInvalidNestedKey = 121,
+ /*!
+ @abstract Invalid file name.
+ A file name can contain only `a-zA-Z0-9_.` characters and should be between 1 and 36 characters.
+ */
+ kPFErrorInvalidFileName = 122,
+ /*!
+ @abstract Invalid ACL. An ACL with an invalid format was saved. This should not happen if you use .
+ */
+ kPFErrorInvalidACL = 123,
+ /*!
+ @abstract The request timed out on the server. Typically this indicates the request is too expensive.
+ */
+ kPFErrorTimeout = 124,
+ /*!
+ @abstract The email address was invalid.
+ */
+ kPFErrorInvalidEmailAddress = 125,
+ /*!
+ A unique field was given a value that is already taken.
+ */
+ kPFErrorDuplicateValue = 137,
+ /*!
+ @abstract Role's name is invalid.
+ */
+ kPFErrorInvalidRoleName = 139,
+ /*!
+ @abstract Exceeded an application quota. Upgrade to resolve.
+ */
+ kPFErrorExceededQuota = 140,
+ /*!
+ @abstract Cloud Code script had an error.
+ */
+ kPFScriptError = 141,
+ /*!
+ @abstract Cloud Code validation failed.
+ */
+ kPFValidationError = 142,
+ /*!
+ @abstract Product purchase receipt is missing.
+ */
+ kPFErrorReceiptMissing = 143,
+ /*!
+ @abstract Product purchase receipt is invalid.
+ */
+ kPFErrorInvalidPurchaseReceipt = 144,
+ /*!
+ @abstract Payment is disabled on this device.
+ */
+ kPFErrorPaymentDisabled = 145,
+ /*!
+ @abstract The product identifier is invalid.
+ */
+ kPFErrorInvalidProductIdentifier = 146,
+ /*!
+ @abstract The product is not found in the App Store.
+ */
+ kPFErrorProductNotFoundInAppStore = 147,
+ /*!
+ @abstract The Apple server response is not valid.
+ */
+ kPFErrorInvalidServerResponse = 148,
+ /*!
+ @abstract Product fails to download due to file system error.
+ */
+ kPFErrorProductDownloadFileSystemFailure = 149,
+ /*!
+ @abstract Fail to convert data to image.
+ */
+ kPFErrorInvalidImageData = 150,
+ /*!
+ @abstract Unsaved file.
+ */
+ kPFErrorUnsavedFile = 151,
+ /*!
+ @abstract Fail to delete file.
+ */
+ kPFErrorFileDeleteFailure = 153,
+ /*!
+ @abstract Application has exceeded its request limit.
+ */
+ kPFErrorRequestLimitExceeded = 155,
+ /*!
+ @abstract Invalid event name.
+ */
+ kPFErrorInvalidEventName = 160,
+ /*!
+ @abstract Username is missing or empty.
+ */
+ kPFErrorUsernameMissing = 200,
+ /*!
+ @abstract Password is missing or empty.
+ */
+ kPFErrorUserPasswordMissing = 201,
+ /*!
+ @abstract Username has already been taken.
+ */
+ kPFErrorUsernameTaken = 202,
+ /*!
+ @abstract Email has already been taken.
+ */
+ kPFErrorUserEmailTaken = 203,
+ /*!
+ @abstract The email is missing, and must be specified.
+ */
+ kPFErrorUserEmailMissing = 204,
+ /*!
+ @abstract A user with the specified email was not found.
+ */
+ kPFErrorUserWithEmailNotFound = 205,
+ /*!
+ @abstract The user cannot be altered by a client without the session.
+ */
+ kPFErrorUserCannotBeAlteredWithoutSession = 206,
+ /*!
+ @abstract Users can only be created through sign up.
+ */
+ kPFErrorUserCanOnlyBeCreatedThroughSignUp = 207,
+ /*!
+ @abstract An existing Facebook account already linked to another user.
+ */
+ kPFErrorFacebookAccountAlreadyLinked = 208,
+ /*!
+ @abstract An existing account already linked to another user.
+ */
+ kPFErrorAccountAlreadyLinked = 208,
+ /*!
+ Error code indicating that the current session token is invalid.
+ */
+ kPFErrorInvalidSessionToken = 209,
+ kPFErrorUserIdMismatch = 209,
+ /*!
+ @abstract Facebook id missing from request.
+ */
+ kPFErrorFacebookIdMissing = 250,
+ /*!
+ @abstract Linked id missing from request.
+ */
+ kPFErrorLinkedIdMissing = 250,
+ /*!
+ @abstract Invalid Facebook session.
+ */
+ kPFErrorFacebookInvalidSession = 251,
+ /*!
+ @abstract Invalid linked session.
+ */
+ kPFErrorInvalidLinkedSession = 251,
+};
+
+///--------------------------------------
+/// @name Blocks
+///--------------------------------------
+
+typedef void (^PFBooleanResultBlock)(BOOL succeeded, NSError *PF_NULLABLE_S error);
+typedef void (^PFIntegerResultBlock)(int number, NSError *PF_NULLABLE_S error);
+typedef void (^PFArrayResultBlock)(NSArray *PF_NULLABLE_S objects, NSError *PF_NULLABLE_S error);
+typedef void (^PFObjectResultBlock)(PFObject *PF_NULLABLE_S object, NSError *PF_NULLABLE_S error);
+typedef void (^PFSetResultBlock)(NSSet *PF_NULLABLE_S channels, NSError *PF_NULLABLE_S error);
+typedef void (^PFUserResultBlock)(PFUser *PF_NULLABLE_S user, NSError *PF_NULLABLE_S error);
+typedef void (^PFDataResultBlock)(NSData *PF_NULLABLE_S data, NSError *PF_NULLABLE_S error);
+typedef void (^PFDataStreamResultBlock)(NSInputStream *PF_NULLABLE_S stream, NSError *PF_NULLABLE_S error);
+typedef void (^PFStringResultBlock)(NSString *PF_NULLABLE_S string, NSError *PF_NULLABLE_S error);
+typedef void (^PFIdResultBlock)(PF_NULLABLE_S id object, NSError *PF_NULLABLE_S error);
+typedef void (^PFProgressBlock)(int percentDone);
+
+///--------------------------------------
+/// @name Deprecated Macros
+///--------------------------------------
+
+#ifndef PARSE_DEPRECATED
+# ifdef __deprecated_msg
+# define PARSE_DEPRECATED(_MSG) __deprecated_msg(_MSG)
+# else
+# ifdef __deprecated
+# define PARSE_DEPRECATED(_MSG) __attribute__((deprecated))
+# else
+# define PARSE_DEPRECATED(_MSG)
+# endif
+# endif
+#endif
+
+///--------------------------------------
+/// @name Extensions Macros
+///--------------------------------------
+
+#ifndef PF_EXTENSION_UNAVAILABLE
+# if PARSE_IOS_ONLY
+# ifdef NS_EXTENSION_UNAVAILABLE_IOS
+# define PF_EXTENSION_UNAVAILABLE(_msg) NS_EXTENSION_UNAVAILABLE_IOS(_msg)
+# else
+# define PF_EXTENSION_UNAVAILABLE(_msg)
+# endif
+# else
+# ifdef NS_EXTENSION_UNAVAILABLE_MAC
+# define PF_EXTENSION_UNAVAILABLE(_msg) NS_EXTENSION_UNAVAILABLE_MAC(_msg)
+# else
+# define PF_EXTENSION_UNAVAILABLE(_msg)
+# endif
+# endif
+#endif
diff --git a/Pods/Parse/PFFile.h b/Pods/Parse/PFFile.h
new file mode 100644
index 0000000..b78e0cb
--- /dev/null
+++ b/Pods/Parse/PFFile.h
@@ -0,0 +1,389 @@
+//
+// PFFile.h
+//
+// Copyright 2011-present Parse Inc. All rights reserved.
+//
+
+#import
+
+#if TARGET_OS_IPHONE
+#import
+#else
+#import
+#endif
+
+PF_ASSUME_NONNULL_BEGIN
+
+@class BFTask;
+
+/*!
+ `PFFile` representes a file of binary data stored on the Parse servers.
+ This can be a image, video, or anything else that an application needs to reference in a non-relational way.
+ */
+@interface PFFile : NSObject
+
+///--------------------------------------
+/// @name Creating a PFFile
+///--------------------------------------
+
+/*!
+ @abstract Creates a file with given data. A name will be assigned to it by the server.
+
+ @param data The contents of the new `PFFile`.
+
+ @returns A new `PFFile`.
+ */
++ (instancetype)fileWithData:(NSData *)data;
+
+/*!
+ @abstract Creates a file with given data and name.
+
+ @param name The name of the new PFFile. The file name must begin with and
+ alphanumeric character, and consist of alphanumeric characters, periods,
+ spaces, underscores, or dashes.
+ @param data The contents of the new `PFFile`.
+
+ @returns A new `PFFile` object.
+ */
++ (instancetype)fileWithName:(PF_NULLABLE NSString *)name data:(NSData *)data;
+
+/*!
+ @abstract Creates a file with the contents of another file.
+
+ @warning This method raises an exception if the file at path is not accessible
+ or if there is not enough disk space left.
+
+ @param name The name of the new `PFFile`. The file name must begin with and alphanumeric character,
+ and consist of alphanumeric characters, periods, spaces, underscores, or dashes.
+ @param path The path to the file that will be uploaded to Parse.
+
+ @returns A new `PFFile` instance.
+ */
++ (instancetype)fileWithName:(PF_NULLABLE NSString *)name contentsAtPath:(NSString *)path;
+
+/*!
+ @abstract Creates a file with the contents of another file.
+
+ @param name The name of the new `PFFile`. The file name must begin with and alphanumeric character,
+ and consist of alphanumeric characters, periods, spaces, underscores, or dashes.
+ @param path The path to the file that will be uploaded to Parse.
+ @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 A new `PFFile` instance or `nil` if the error occured.
+ */
++ (instancetype)fileWithName:(PF_NULLABLE NSString *)name contentsAtPath:(NSString *)path error:(NSError **)error;
+
+/*!
+ @abstract Creates a file with given data, name and content type.
+
+ @warning This method raises an exception if the data supplied is not accessible or could not be saved.
+
+ @param name The name of the new `PFFile`. The file name must begin with and alphanumeric character,
+ and consist of alphanumeric characters, periods, spaces, underscores, or dashes.
+ @param data The contents of the new `PFFile`.
+ @param contentType Represents MIME type of the data.
+
+ @returns A new `PFFile` instance.
+ */
++ (instancetype)fileWithName:(PF_NULLABLE NSString *)name
+ data:(NSData *)data
+ contentType:(PF_NULLABLE NSString *)contentType;
+
+/*!
+ @abstract Creates a file with given data, name and content type.
+
+ @param name The name of the new `PFFile`. The file name must begin with and alphanumeric character,
+ and consist of alphanumeric characters, periods, spaces, underscores, or dashes.
+ @param data The contents of the new `PFFile`.
+ @param contentType Represents MIME type of the data.
+ @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 A new `PFFile` instance or `nil` if the error occured.
+ */
++ (instancetype)fileWithName:(PF_NULLABLE NSString *)name
+ data:(NSData *)data
+ contentType:(PF_NULLABLE NSString *)contentType
+ error:(NSError **)error;
+
+/*!
+ @abstract Creates a file with given data and content type.
+
+ @param data The contents of the new `PFFile`.
+ @param contentType Represents MIME type of the data.
+
+ @returns A new `PFFile` object.
+ */
++ (instancetype)fileWithData:(NSData *)data contentType:(PF_NULLABLE NSString *)contentType;
+
+/*!
+ @abstract The name of the file.
+
+ @discussion Before the file is saved, this is the filename given by
+ the user. After the file is saved, that name gets prefixed with a unique
+ identifier.
+ */
+@property (nonatomic, copy, readonly) NSString *name;
+
+/*!
+ @abstract The url of the file.
+ */
+@property (PF_NULLABLE_PROPERTY nonatomic, copy, readonly) NSString *url;
+
+///--------------------------------------
+/// @name Storing Data with Parse
+///--------------------------------------
+
+/*!
+ @abstract Whether the file has been uploaded for the first time.
+ */
+@property (nonatomic, assign, readonly) BOOL isDirty;
+
+/*!
+ @abstract Saves the file *synchronously*.
+
+ @returns Returns whether the save succeeded.
+ */
+- (BOOL)save;
+
+/*!
+ @abstract Saves the file *synchronously* and sets an error if it occurs.
+
+ @param error Pointer to an `NSError` that will be set if necessary.
+
+ @returns Returns whether the save succeeded.
+ */
+- (BOOL)save:(NSError **)error;
+
+/*!
+ @abstract Saves the file *asynchronously*.
+
+ @returns The task, that encapsulates the work being done.
+ */
+- (BFTask *)saveInBackground;
+
+/*!
+ @abstract Saves the file *asynchronously*
+
+ @param progressBlock The block should have the following argument signature: `^(int percentDone)`
+
+ @returns The task, that encapsulates the work being done.
+ */
+- (BFTask *)saveInBackgroundWithProgressBlock:(PF_NULLABLE PFProgressBlock)progressBlock;
+
+/*!
+ @abstract Saves the file *asynchronously* and executes the given block.
+
+ @param block The block should have the following argument signature: `^(BOOL succeeded, NSError *error)`.
+ */
+- (void)saveInBackgroundWithBlock:(PF_NULLABLE PFBooleanResultBlock)block;
+
+/*!
+ @abstract Saves the file *asynchronously* and executes the given block.
+
+ @discussion This method will execute the progressBlock periodically with the percent progress.
+ `progressBlock` will get called with `100` before `resultBlock` is called.
+
+ @param block The block should have the following argument signature: `^(BOOL succeeded, NSError *error)`
+ @param progressBlock The block should have the following argument signature: `^(int percentDone)`
+ */
+- (void)saveInBackgroundWithBlock:(PF_NULLABLE PFBooleanResultBlock)block
+ progressBlock:(PF_NULLABLE PFProgressBlock)progressBlock;
+
+/*
+ @abstract Saves the file *asynchronously* and calls the given callback.
+
+ @param target The object to call selector on.
+ @param selector The selector to call.
+ It should have the following signature: `(void)callbackWithResult:(NSNumber *)result error:(NSError *)error`.
+ `error` will be `nil` on success and set if there was an error.
+ `[result boolValue]` will tell you whether the call succeeded or not.
+ */
+- (void)saveInBackgroundWithTarget:(PF_NULLABLE_S id)target selector:(PF_NULLABLE_S SEL)selector;
+
+///--------------------------------------
+/// @name Getting Data from Parse
+///--------------------------------------
+
+/*!
+ @abstract Whether the data is available in memory or needs to be downloaded.
+ */
+@property (assign, readonly) BOOL isDataAvailable;
+
+/*!
+ @abstract *Synchronously* gets the data from cache if available or fetches its contents from the network.
+
+ @returns The `NSData` object containing file data. Returns `nil` if there was an error in fetching.
+ */
+- (PF_NULLABLE NSData *)getData;
+
+/*!
+ @abstract This method is like but avoids ever holding the entire `PFFile` contents in memory at once.
+
+ @discussion This can help applications with many large files avoid memory warnings.
+
+ @returns A stream containing the data. Returns `nil` if there was an error in fetching.
+ */
+- (PF_NULLABLE NSInputStream *)getDataStream;
+
+/*!
+ @abstract *Synchronously* gets the data from cache if available or fetches its contents from the network.
+ Sets an error if it occurs.
+
+ @param error Pointer to an `NSError` that will be set if necessary.
+
+ @returns The `NSData` object containing file data. Returns `nil` if there was an error in fetching.
+ */
+- (PF_NULLABLE NSData *)getData:(NSError **)error;
+
+/*!
+ @abstract This method is like but avoids ever holding the entire `PFFile` contents in memory at once.
+
+ @param error Pointer to an `NSError` that will be set if necessary.
+
+ @returns A stream containing the data. Returns nil if there was an error in
+ fetching.
+ */
+- (PF_NULLABLE NSInputStream *)getDataStream:(NSError **)error;
+
+/*!
+ @abstract This method is like but it fetches asynchronously to avoid blocking the current thread.
+
+ @see getData
+
+ @returns The task, that encapsulates the work being done.
+ */
+- (BFTask *)getDataInBackground;
+
+/*!
+ @abstract This method is like but it fetches asynchronously to avoid blocking the current thread.
+
+ @discussion This can help applications with many large files avoid memory warnings.
+
+ @see getData
+
+ @param progressBlock The block should have the following argument signature: ^(int percentDone)
+
+ @returns The task, that encapsulates the work being done.
+ */
+- (BFTask *)getDataInBackgroundWithProgressBlock:(PF_NULLABLE PFProgressBlock)progressBlock;
+
+/*!
+ @abstract This method is like but avoids
+ ever holding the entire `PFFile` contents in memory at once.
+
+ @discussion This can help applications with many large files avoid memory warnings.
+
+ @returns The task, that encapsulates the work being done.
+ */
+- (BFTask *)getDataStreamInBackground;
+
+/*!
+ @abstract This method is like , but yields a live-updating stream.
+
+ @discussion Instead of , which yields a stream that can be read from only after the request has
+ completed, this method gives you a stream directly written to by the HTTP session. As this stream is not pre-buffered,
+ it is strongly advised to use the `NSStreamDelegate` methods, in combination with a run loop, to consume the data in
+ the stream, to do proper async file downloading.
+
+ @note You MUST open this stream before reading from it.
+ @note Do NOT call on this task from the main thread. It may result in a deadlock.
+
+ @returns A task that produces a *live* stream that is being written to with the data from the server.
+ */
+- (BFTask *)getDataDownloadStreamInBackground;
+
+/*!
+ @abstract This method is like but avoids
+ ever holding the entire `PFFile` contents in memory at once.
+
+ @discussion This can help applications with many large files avoid memory warnings.
+ @param progressBlock The block should have the following argument signature: ^(int percentDone)
+
+ @returns The task, that encapsulates the work being done.
+ */
+- (BFTask *)getDataStreamInBackgroundWithProgressBlock:(PF_NULLABLE PFProgressBlock)progressBlock;
+
+/*!
+ @abstract This method is like , but yields a live-updating stream.
+
+ @discussion Instead of , which yields a stream that can be read from only after the request has
+ completed, this method gives you a stream directly written to by the HTTP session. As this stream is not pre-buffered,
+ it is strongly advised to use the `NSStreamDelegate` methods, in combination with a run loop, to consume the data in
+ the stream, to do proper async file downloading.
+
+ @note You MUST open this stream before reading from it.
+ @note Do NOT call on this task from the main thread. It may result in a deadlock.
+
+ @param progressBlock The block should have the following argument signature: `^(int percentDone)`
+
+ @returns A task that produces a *live* stream that is being written to with the data from the server.
+ */
+- (BFTask *)getDataDownloadStreamInBackgroundWithProgressBlock:(PF_NULLABLE PFProgressBlock)progressBlock;
+
+/*!
+ @abstract *Asynchronously* gets the data from cache if available or fetches its contents from the network.
+
+ @param block The block should have the following argument signature: `^(NSData *result, NSError *error)`
+ */
+- (void)getDataInBackgroundWithBlock:(PF_NULLABLE PFDataResultBlock)block;
+
+/*!
+ @abstract This method is like but avoids
+ ever holding the entire `PFFile` contents in memory at once.
+
+ @discussion This can help applications with many large files avoid memory warnings.
+
+ @param block The block should have the following argument signature: `(NSInputStream *result, NSError *error)`
+ */
+- (void)getDataStreamInBackgroundWithBlock:(PF_NULLABLE PFDataStreamResultBlock)block;
+
+/*!
+ @abstract *Asynchronously* gets the data from cache if available or fetches its contents from the network.
+
+ @discussion This method will execute the progressBlock periodically with the percent progress.
+ `progressBlock` will get called with `100` before `resultBlock` is called.
+
+ @param resultBlock The block should have the following argument signature: ^(NSData *result, NSError *error)
+ @param progressBlock The block should have the following argument signature: ^(int percentDone)
+ */
+- (void)getDataInBackgroundWithBlock:(PF_NULLABLE PFDataResultBlock)resultBlock
+ progressBlock:(PF_NULLABLE PFProgressBlock)progressBlock;
+
+/*!
+ @abstract This method is like but avoids
+ ever holding the entire `PFFile` contents in memory at once.
+
+ @discussion This can help applications with many large files avoid memory warnings.
+
+ @param resultBlock The block should have the following argument signature: `^(NSInputStream *result, NSError *error)`.
+ @param progressBlock The block should have the following argument signature: `^(int percentDone)`.
+ */
+- (void)getDataStreamInBackgroundWithBlock:(PF_NULLABLE PFDataStreamResultBlock)resultBlock
+ progressBlock:(PF_NULLABLE PFProgressBlock)progressBlock;
+
+/*
+ @abstract *Asynchronously* gets the data from cache if available or fetches its contents from the network.
+
+ @param target The object to call selector on.
+ @param selector The selector to call.
+ It should have the following signature: `(void)callbackWithResult:(NSData *)result error:(NSError *)error`.
+ `error` will be `nil` on success and set if there was an error.
+ */
+- (void)getDataInBackgroundWithTarget:(PF_NULLABLE_S id)target selector:(PF_NULLABLE_S SEL)selector;
+
+///--------------------------------------
+/// @name Interrupting a Transfer
+///--------------------------------------
+
+/*!
+ @abstract Cancels the current request (upload or download of file).
+ */
+- (void)cancel;
+
+@end
+
+PF_ASSUME_NONNULL_END
diff --git a/Pods/Parse/PFGeoPoint.h b/Pods/Parse/PFGeoPoint.h
new file mode 100644
index 0000000..6861946
--- /dev/null
+++ b/Pods/Parse/PFGeoPoint.h
@@ -0,0 +1,115 @@
+//
+// PFGeoPoint.h
+//
+// Copyright 2011-present Parse Inc. All rights reserved.
+//
+
+#import
+#import
+
+#if TARGET_OS_IPHONE
+#import
+#else
+#import
+#endif
+
+PF_ASSUME_NONNULL_BEGIN
+
+@class PFGeoPoint;
+
+typedef void(^PFGeoPointResultBlock)(PFGeoPoint *PF_NULLABLE_S geoPoint, NSError *PF_NULLABLE_S error);
+
+/*!
+ `PFGeoPoint` may be used to embed a latitude / longitude point as the value for a key in a .
+ It could be used to perform queries in a geospatial manner using <[PFQuery whereKey:nearGeoPoint:]>.
+
+ Currently, instances of may only have one key associated with a `PFGeoPoint` type.
+ */
+@interface PFGeoPoint : NSObject
+
+///--------------------------------------
+/// @name Creating a Geo Point
+///--------------------------------------
+
+/*!
+ @abstract Create a PFGeoPoint object. Latitude and longitude are set to `0.0`.
+
+ @returns Returns a new `PFGeoPoint`.
+ */
++ (PFGeoPoint *)geoPoint;
+
+/*!
+ @abstract Creates a new `PFGeoPoint` object for the given `CLLocation`, set to the location's coordinates.
+
+ @param location Instace of `CLLocation`, with set latitude and longitude.
+
+ @returns Returns a new PFGeoPoint at specified location.
+ */
++ (PFGeoPoint *)geoPointWithLocation:(PF_NULLABLE CLLocation *)location;
+
+/*!
+ @abstract Create a new `PFGeoPoint` object with the specified latitude and longitude.
+
+ @param latitude Latitude of point in degrees.
+ @param longitude Longitude of point in degrees.
+
+ @returns New point object with specified latitude and longitude.
+ */
++ (PFGeoPoint *)geoPointWithLatitude:(double)latitude longitude:(double)longitude;
+
+/*!
+ @abstract Fetches the current device location and executes a block with a new `PFGeoPoint` object.
+
+ @param resultBlock A block which takes the newly created `PFGeoPoint` as an argument.
+ It should have the following argument signature: `^(PFGeoPoint *geoPoint, NSError *error)`
+ */
++ (void)geoPointForCurrentLocationInBackground:(PF_NULLABLE PFGeoPointResultBlock)resultBlock;
+
+///--------------------------------------
+/// @name Controlling Position
+///--------------------------------------
+
+/*!
+ @abstract Latitude of point in degrees. Valid range is from `-90.0` to `90.0`.
+ */
+@property (nonatomic, assign) double latitude;
+
+/*!
+ @abstract Longitude of point in degrees. Valid range is from `-180.0` to `180.0`.
+ */
+@property (nonatomic, assign) double longitude;
+
+///--------------------------------------
+/// @name Calculating Distance
+///--------------------------------------
+
+/*!
+ @abstract Get distance in radians from this point to specified point.
+
+ @param point `PFGeoPoint` that represents the location of other point.
+
+ @returns Distance in radians between the receiver and `point`.
+ */
+- (double)distanceInRadiansTo:(PF_NULLABLE PFGeoPoint *)point;
+
+/*!
+ @abstract Get distance in miles from this point to specified point.
+
+ @param point `PFGeoPoint` that represents the location of other point.
+
+ @returns Distance in miles between the receiver and `point`.
+ */
+- (double)distanceInMilesTo:(PF_NULLABLE PFGeoPoint *)point;
+
+/*!
+ @abstract Get distance in kilometers from this point to specified point.
+
+ @param point `PFGeoPoint` that represents the location of other point.
+
+ @returns Distance in kilometers between the receiver and `point`.
+ */
+- (double)distanceInKilometersTo:(PF_NULLABLE PFGeoPoint *)point;
+
+@end
+
+PF_ASSUME_NONNULL_END
diff --git a/Pods/Parse/PFInstallation.h b/Pods/Parse/PFInstallation.h
new file mode 100644
index 0000000..57e4cee
--- /dev/null
+++ b/Pods/Parse/PFInstallation.h
@@ -0,0 +1,116 @@
+//
+// PFInstallation.h
+//
+// Copyright 2011-present Parse Inc. All rights reserved.
+//
+
+#import
+
+#if TARGET_OS_IPHONE
+#import
+#import
+#import
+#else
+#import
+#import
+#import
+#endif
+
+PF_ASSUME_NONNULL_BEGIN
+
+/*!
+ A Parse Framework Installation Object that is a local representation of an
+ installation persisted to the Parse cloud. This class is a subclass of a
+ , and retains the same functionality of a PFObject, but also extends
+ it with installation-specific fields and related immutability and validity
+ checks.
+
+ A valid `PFInstallation` can only be instantiated via
+ <[PFInstallation currentInstallation]> because the required identifier fields
+ are readonly. The and fields are also readonly properties which
+ are automatically updated to match the device's time zone and application badge
+ when the `PFInstallation` is saved, thus these fields might not reflect the
+ latest device state if the installation has not recently been saved.
+
+ `PFInstallation` objects which have a valid and are saved to
+ the Parse cloud can be used to target push notifications.
+ */
+
+@interface PFInstallation : PFObject
+
+///--------------------------------------
+/// @name Accessing the Current Installation
+///--------------------------------------
+
+/*!
+ @abstract Gets the currently-running installation from disk and returns an instance of it.
+
+ @discussion If this installation is not stored on disk, returns a `PFInstallation`
+ with and fields set to those of the
+ current installation.
+
+ @result Returns a `PFInstallation` that represents the currently-running installation.
+ */
++ (instancetype)currentInstallation;
+
+///--------------------------------------
+/// @name Installation Properties
+///--------------------------------------
+
+/*!
+ @abstract The device type for the `PFInstallation`.
+ */
+@property (nonatomic, strong, readonly) NSString *deviceType;
+
+/*!
+ @abstract The installationId for the `PFInstallation`.
+ */
+@property (nonatomic, strong, readonly) NSString *installationId;
+
+/*!
+ @abstract The device token for the `PFInstallation`.
+ */
+@property (PF_NULLABLE_PROPERTY nonatomic, strong) NSString *deviceToken;
+
+/*!
+ @abstract The badge for the `PFInstallation`.
+ */
+@property (nonatomic, assign) NSInteger badge;
+
+/*!
+ @abstract The name of the time zone for the `PFInstallation`.
+ */
+@property (PF_NULLABLE_PROPERTY nonatomic, strong, readonly) NSString *timeZone;
+
+/*!
+ @abstract The channels for the `PFInstallation`.
+ */
+@property (PF_NULLABLE_PROPERTY nonatomic, strong) NSArray *channels;
+
+/*!
+ @abstract Sets the device token string property from an `NSData`-encoded token.
+
+ @param deviceTokenData A token that identifies the device.
+ */
+- (void)setDeviceTokenFromData:(PF_NULLABLE NSData *)deviceTokenData;
+
+///--------------------------------------
+/// @name Querying for Installations
+///--------------------------------------
+
+/*!
+ @abstract Creates a for `PFInstallation` objects.
+
+ @discussion Only the following types of queries are allowed for installations:
+
+ - `[query getObjectWithId:]`
+ - `[query whereKey:@"installationId" equalTo:]`
+ - `[query whereKey:@"installationId" matchesKey: inQuery:]`
+
+ You can add additional query conditions, but one of the above must appear as a top-level `AND` clause in the query.
+ */
++ (PF_NULLABLE PFQuery *)query;
+
+@end
+
+PF_ASSUME_NONNULL_END
diff --git a/Pods/Parse/PFNetworkActivityIndicatorManager.h b/Pods/Parse/PFNetworkActivityIndicatorManager.h
new file mode 100644
index 0000000..9095271
--- /dev/null
+++ b/Pods/Parse/PFNetworkActivityIndicatorManager.h
@@ -0,0 +1,67 @@
+//
+// PFNetworkActivityIndicatorManager.h
+//
+// Copyright 2011-present Parse Inc. All rights reserved.
+//
+
+#import
+#import
+
+#import
+
+PF_ASSUME_NONNULL_BEGIN
+
+/*!
+ `PFNetworkActivityIndicatorManager` manages the state of the network activity indicator in the status bar.
+ When enabled, it will start managing the network activity indicator in the status bar,
+ according to the network operations that are performed by Parse SDK.
+
+ The number of active requests is incremented or decremented like a stack or a semaphore,
+ the activity indicator will animate, as long as the number is greater than zero.
+ */
+@interface PFNetworkActivityIndicatorManager : NSObject
+
+/*!
+ A Boolean value indicating whether the manager is enabled.
+ If `YES` - the manager will start managing the status bar network activity indicator,
+ according to the network operations that are performed by Parse SDK.
+ The default value is `YES`.
+ */
+@property (nonatomic, assign, getter = isEnabled) BOOL enabled;
+
+/*!
+ A Boolean value indicating whether the network activity indicator is currently displayed in the status bar.
+ */
+@property (nonatomic, assign, readonly, getter = isNetworkActivityIndicatorVisible) BOOL networkActivityIndicatorVisible;
+
+/*!
+ The value that indicates current network activities count.
+ */
+@property (nonatomic, assign, readonly) NSUInteger networkActivityCount;
+
+/*!
+ @abstract Returns the shared network activity indicator manager object for the system.
+
+ @returns The systemwide network activity indicator manager.
+ */
++ (instancetype)sharedManager;
+
+/*!
+ @abstract Increments the number of active network requests.
+
+ @discussion If this number was zero before incrementing,
+ this will start animating network activity indicator in the status bar.
+ */
+- (void)incrementActivityCount;
+
+/*!
+ @abstract Decrements the number of active network requests.
+
+ @discussion If this number becomes zero after decrementing,
+ this will stop animating network activity indicator in the status bar.
+ */
+- (void)decrementActivityCount;
+
+@end
+
+PF_ASSUME_NONNULL_END
diff --git a/Pods/Parse/PFNullability.h b/Pods/Parse/PFNullability.h
new file mode 100644
index 0000000..507a91e
--- /dev/null
+++ b/Pods/Parse/PFNullability.h
@@ -0,0 +1,44 @@
+//
+// PFNullability.h
+//
+// Copyright 2011-present Parse Inc. All rights reserved.
+//
+
+#ifndef Parse_PFNullability_h
+#define Parse_PFNullability_h
+
+///--------------------------------------
+/// @name Nullability Annotation Support
+///--------------------------------------
+
+#if __has_feature(nullability)
+# define PF_NONNULL nonnull
+# define PF_NONNULL_S __nonnull
+# define PF_NULLABLE nullable
+# define PF_NULLABLE_S __nullable
+# define PF_NULLABLE_PROPERTY nullable,
+#else
+# define PF_NONNULL
+# define PF_NONNULL_S
+# define PF_NULLABLE
+# define PF_NULLABLE_S
+# define PF_NULLABLE_PROPERTY
+#endif
+
+#if __has_feature(assume_nonnull)
+# ifdef NS_ASSUME_NONNULL_BEGIN
+# define PF_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN
+# else
+# define PF_ASSUME_NONNULL_BEGIN _Pragma("clang assume_nonnull begin")
+# endif
+# ifdef NS_ASSUME_NONNULL_END
+# define PF_ASSUME_NONNULL_END NS_ASSUME_NONNULL_END
+# else
+# define PF_ASSUME_NONNULL_END _Pragma("clang assume_nonnull end")
+# endif
+#else
+# define PF_ASSUME_NONNULL_BEGIN
+# define PF_ASSUME_NONNULL_END
+#endif
+
+#endif
diff --git a/Pods/Parse/PFObject+Subclass.h b/Pods/Parse/PFObject+Subclass.h
new file mode 100644
index 0000000..289faeb
--- /dev/null
+++ b/Pods/Parse/PFObject+Subclass.h
@@ -0,0 +1,127 @@
+//
+// PFObject+Subclass.h
+//
+// Copyright 2011-present Parse Inc. All rights reserved.
+//
+
+#import
+
+#if TARGET_OS_IPHONE
+#import
+#import
+#else
+#import
+#import
+#endif
+
+PF_ASSUME_NONNULL_BEGIN
+
+@class PFQuery;
+
+/*!
+ ### Subclassing Notes
+
+ Developers can subclass `PFObject` for a more native object-oriented class structure.
+ Strongly-typed subclasses of `PFObject` must conform to the protocol
+ and must call before <[Parse setApplicationId:clientKey:]> is called.
+ After this it will be returned by and other `PFObject` factories.
+
+ All methods in except for <[PFSubclassing parseClassName]>
+ are already implemented in the `PFObject+Subclass` category.
+
+ Including `PFObject+Subclass.h` in your implementation file provides these implementations automatically.
+
+ Subclasses support simpler initializers, query syntax, and dynamic synthesizers.
+ The following shows an example subclass:
+
+ \@interface MYGame : PFObject
+
+ // Accessing this property is the same as objectForKey:@"title"
+ @property (nonatomic, strong) NSString *title;
+
+ + (NSString *)parseClassName;
+
+ @end
+
+
+ @implementation MYGame
+
+ @dynamic title;
+
+ + (NSString *)parseClassName {
+ return @"Game";
+ }
+
+ @end
+
+
+ MYGame *game = [[MYGame alloc] init];
+ game.title = @"Bughouse";
+ [game saveInBackground];
+ */
+@interface PFObject (Subclass)
+
+///--------------------------------------
+/// @name Methods for Subclasses
+///--------------------------------------
+
+/*!
+ @abstract Creates an instance of the registered subclass with this class's .
+
+ @discussion This helps a subclass ensure that it can be subclassed itself.
+ For example, `[PFUser object]` will return a `MyUser` object if `MyUser` is a registered subclass of `PFUser`.
+ For this reason, `[MyClass object]` is preferred to `[[MyClass alloc] init]`.
+ This method can only be called on subclasses which conform to `PFSubclassing`.
+ A default implementation is provided by `PFObject` which should always be sufficient.
+ */
++ (instancetype)object;
+
+/*!
+ @abstract Creates a reference to an existing `PFObject` for use in creating associations between `PFObjects`.
+
+ @discussion Calling on this object will return `NO` until or has been called.
+ This method can only be called on subclasses which conform to .
+ A default implementation is provided by `PFObject` which should always be sufficient.
+ No network request will be made.
+
+ @param objectId The object id for the referenced object.
+
+ @returns An instance of `PFObject` without data.
+ */
++ (instancetype)objectWithoutDataWithObjectId:(PF_NULLABLE NSString *)objectId;
+
+/*!
+ @abstract Registers an Objective-C class for Parse to use for representing a given Parse class.
+
+ @discussion Once this is called on a `PFObject` subclass, any `PFObject` Parse creates with a class name
+ that matches `[self parseClassName]` will be an instance of subclass.
+ This method can only be called on subclasses which conform to .
+ A default implementation is provided by `PFObject` which should always be sufficient.
+ */
++ (void)registerSubclass;
+
+/*!
+ @abstract Returns a query for objects of type .
+
+ @discussion This method can only be called on subclasses which conform to .
+ A default implementation is provided by which should always be sufficient.
+ */
++ (PF_NULLABLE PFQuery *)query;
+
+/*!
+ @abstract Returns a query for objects of type with a given predicate.
+
+ @discussion A default implementation is provided by which should always be sufficient.
+ @warning This method can only be called on subclasses which conform to .
+
+ @param predicate The predicate to create conditions from.
+
+ @returns An instance of .
+
+ @see [PFQuery queryWithClassName:predicate:]
+ */
++ (PF_NULLABLE PFQuery *)queryWithPredicate:(PF_NULLABLE NSPredicate *)predicate;
+
+@end
+
+PF_ASSUME_NONNULL_END
diff --git a/Pods/Parse/PFObject.h b/Pods/Parse/PFObject.h
new file mode 100644
index 0000000..ab45c91
--- /dev/null
+++ b/Pods/Parse/PFObject.h
@@ -0,0 +1,1423 @@
+//
+// PFObject.h
+//
+// Copyright 2011-present Parse Inc. All rights reserved.
+//
+
+#import
+
+#if TARGET_OS_IPHONE
+#import
+#import
+#else
+#import
+#import
+#endif
+
+PF_ASSUME_NONNULL_BEGIN
+
+@protocol PFSubclassing;
+@class BFTask;
+@class PFRelation;
+
+/*!
+ The name of the default pin that for PFObject local data store.
+ */
+extern NSString *const PFObjectDefaultPin;
+
+/*!
+ The `PFObject` class is a local representation of data persisted to the Parse cloud.
+ This is the main class that is used to interact with objects in your app.
+ */
+NS_REQUIRES_PROPERTY_DEFINITIONS
+@interface PFObject : NSObject {
+ BOOL dirty;
+
+ // An array of NSDictionary of NSString -> PFFieldOperation.
+ // Each dictionary has a subset of the object's keys as keys, and the
+ // changes to the value for that key as its value.
+ // There is always at least one dictionary of pending operations.
+ // Every time a save is started, a new dictionary is added to the end.
+ // Whenever a save completes, the new data is put into fetchedData, and
+ // a dictionary is removed from the start.
+ NSMutableArray *PF_NULLABLE_S operationSetQueue;
+
+ // Our best estimate as to what the current data is, based on
+ // the last fetch from the server, and the set of pending operations.
+ NSMutableDictionary *PF_NULLABLE_S estimatedData;
+}
+
+///--------------------------------------
+/// @name Creating a PFObject
+///--------------------------------------
+
+/*!
+ @abstract Creates a new PFObject with a class name.
+
+ @param className A class name can be any alphanumeric string that begins with a letter.
+ It represents an object in your app, like a 'User' or a 'Document'.
+
+ @returns Returns the object that is instantiated with the given class name.
+ */
++ (instancetype)objectWithClassName:(NSString *)className;
+
+/*!
+ @abstract Creates a reference to an existing PFObject for use in creating associations between PFObjects.
+
+ @discussion Calling on this object will return `NO` until has been called.
+ No network request will be made.
+
+ @param className The object's class.
+ @param objectId The object id for the referenced object.
+
+ @returns A `PFObject` instance without data.
+ */
++ (instancetype)objectWithoutDataWithClassName:(NSString *)className
+ objectId:(PF_NULLABLE NSString *)objectId;
+
+/*!
+ @abstract Creates a new `PFObject` with a class name, initialized with data
+ constructed from the specified set of objects and keys.
+
+ @param className The object's class.
+ @param dictionary An `NSDictionary` of keys and objects to set on the new `PFObject`.
+
+ @returns A PFObject with the given class name and set with the given data.
+ */
++ (PFObject *)objectWithClassName:(NSString *)className
+ dictionary:(PF_NULLABLE NSDictionary *)dictionary;
+
+/*!
+ @abstract Initializes a new empty `PFObject` instance with a class name.
+
+ @param newClassName A class name can be any alphanumeric string that begins with a letter.
+ It represents an object in your app, like a 'User' or a 'Document'.
+
+ @returns Returns the object that is instantiated with the given class name.
+ */
+- (instancetype)initWithClassName:(NSString *)newClassName;
+
+///--------------------------------------
+/// @name Managing Object Properties
+///--------------------------------------
+
+/*!
+ @abstract The class name of the object.
+ */
+@property (strong, readonly) NSString *parseClassName;
+
+/*!
+ @abstract The id of the object.
+ */
+@property (PF_NULLABLE_PROPERTY nonatomic, strong) NSString *objectId;
+
+/*!
+ @abstract When the object was last updated.
+ */
+@property (PF_NULLABLE_PROPERTY nonatomic, strong, readonly) NSDate *updatedAt;
+
+/*!
+ @abstract When the object was created.
+ */
+@property (PF_NULLABLE_PROPERTY nonatomic, strong, readonly) NSDate *createdAt;
+
+/*!
+ @abstract The ACL for this object.
+ */
+@property (PF_NULLABLE_PROPERTY nonatomic, strong) PFACL *ACL;
+
+/*!
+ @abstract Returns an array of the keys contained in this object.
+
+ @discussion This does not include `createdAt`, `updatedAt`, `authData`, or `objectId`.
+ It does include things like username and ACL.
+ */
+- (NSArray *)allKeys;
+
+///--------------------------------------
+/// @name Accessors
+///--------------------------------------
+
+/*!
+ @abstract Returns the value associated with a given key.
+
+ @param key The key for which to return the corresponding value.
+ */
+- (PF_NULLABLE_S id)objectForKey:(NSString *)key;
+
+/*!
+ @abstract Sets the object associated with a given key.
+
+ @param object The object for `key`. A strong reference to the object is maintaned by PFObject.
+ Raises an `NSInvalidArgumentException` if `object` is `nil`.
+ If you need to represent a `nil` value - use `NSNull`.
+ @param key The key for `object`.
+ Raises an `NSInvalidArgumentException` if `key` is `nil`.
+
+ @see setObject:forKeyedSubscript:
+ */
+- (void)setObject:(id)object forKey:(NSString *)key;
+
+/*!
+ @abstract Unsets a key on the object.
+
+ @param key The key.
+ */
+- (void)removeObjectForKey:(NSString *)key;
+
+/*!
+ @abstract Returns the value associated with a given key.
+
+ @discussion This method enables usage of literal syntax on `PFObject`.
+ E.g. `NSString *value = object[@"key"];`
+
+ @param key The key for which to return the corresponding value.
+
+ @see objectForKey:
+ */
+- (PF_NULLABLE_S id)objectForKeyedSubscript:(NSString *)key;
+
+/*!
+ @abstract Returns the value associated with a given key.
+
+ @discussion This method enables usage of literal syntax on `PFObject`.
+ E.g. `object[@"key"] = @"value";`
+
+ @param object The object for `key`. A strong reference to the object is maintaned by PFObject.
+ Raises an `NSInvalidArgumentException` if `object` is `nil`.
+ If you need to represent a `nil` value - use `NSNull`.
+ @param key The key for `object`.
+ Raises an `NSInvalidArgumentException` if `key` is `nil`.
+
+ @see setObject:forKey:
+ */
+- (void)setObject:(PF_NULLABLE_S id)object forKeyedSubscript:(NSString *)key;
+
+/*!
+ @abstract Returns the relation object associated with the given key.
+
+ @param key The key that the relation is associated with.
+ */
+- (PFRelation *)relationForKey:(NSString *)key;
+
+/*!
+ @abstract Returns the relation object associated with the given key.
+
+ @param key The key that the relation is associated with.
+
+ @deprecated Please use `[PFObject relationForKey:]` instead.
+ */
+- (PFRelation *)relationforKey:(NSString *)key PARSE_DEPRECATED("Please use -relationForKey: instead.");
+
+///--------------------------------------
+/// @name Array Accessors
+///--------------------------------------
+
+/*!
+ @abstract Adds an object to the end of the array associated with a given key.
+
+ @param object The object to add.
+ @param key The key.
+ */
+- (void)addObject:(id)object forKey:(NSString *)key;
+
+/*!
+ @abstract Adds the objects contained in another array to the end of the array associated with a given key.
+
+ @param objects The array of objects to add.
+ @param key The key.
+ */
+- (void)addObjectsFromArray:(NSArray *)objects forKey:(NSString *)key;
+
+/*!
+ @abstract Adds an object to the array associated with a given key, only if it is not already present in the array.
+
+ @discussion The position of the insert is not guaranteed.
+
+ @param object The object to add.
+ @param key The key.
+ */
+- (void)addUniqueObject:(id)object forKey:(NSString *)key;
+
+/*!
+ @abstract Adds the objects contained in another array to the array associated with a given key,
+ only adding elements which are not already present in the array.
+
+ @dicsussion The position of the insert is not guaranteed.
+
+ @param objects The array of objects to add.
+ @param key The key.
+ */
+- (void)addUniqueObjectsFromArray:(NSArray *)objects forKey:(NSString *)key;
+
+/*!
+ @abstract Removes all occurrences of an object from the array associated with a given key.
+
+ @param object The object to remove.
+ @param key The key.
+ */
+- (void)removeObject:(id)object forKey:(NSString *)key;
+
+/*!
+ @abstract Removes all occurrences of the objects contained in another array from the array associated with a given key.
+
+ @param objects The array of objects to remove.
+ @param key The key.
+ */
+- (void)removeObjectsInArray:(NSArray *)objects forKey:(NSString *)key;
+
+///--------------------------------------
+/// @name Increment
+///--------------------------------------
+
+/*!
+ @abstract Increments the given key by `1`.
+
+ @param key The key.
+ */
+- (void)incrementKey:(NSString *)key;
+
+/*!
+ @abstract Increments the given key by a number.
+
+ @param key The key.
+ @param amount The amount to increment.
+ */
+- (void)incrementKey:(NSString *)key byAmount:(NSNumber *)amount;
+
+///--------------------------------------
+/// @name Saving Objects
+///--------------------------------------
+
+/*!
+ @abstract *Synchronously* saves the `PFObject`.
+
+ @returns Returns whether the save succeeded.
+ */
+- (BOOL)save;
+
+/*!
+ @abstract *Synchronously* saves the `PFObject` and sets an error if it occurs.
+
+ @param error Pointer to an NSError that will be set if necessary.
+
+ @returns Returns whether the save succeeded.
+ */
+- (BOOL)save:(NSError **)error;
+
+/*!
+ @abstract Saves the `PFObject` *asynchronously*.
+
+ @returns The task that encapsulates the work being done.
+ */
+- (BFTask *)saveInBackground;
+
+/*!
+ @abstract Saves the `PFObject` *asynchronously* and executes the given callback block.
+
+ @param block The block to execute.
+ It should have the following argument signature: `^(BOOL succeeded, NSError *error)`.
+ */
+- (void)saveInBackgroundWithBlock:(PF_NULLABLE PFBooleanResultBlock)block;
+
+/*
+ @abstract Saves the `PFObject` asynchronously and calls the given callback.
+
+ @param target The object to call selector on.
+ @param selector The selector to call.
+ It should have the following signature: `(void)callbackWithResult:(NSNumber *)result error:(NSError *)error`.
+ `error` will be `nil` on success and set if there was an error.
+ `[result boolValue]` will tell you whether the call succeeded or not.
+ */
+- (void)saveInBackgroundWithTarget:(PF_NULLABLE_S id)target selector:(PF_NULLABLE_S SEL)selector;
+
+/*!
+ @abstract Saves this object to the server at some unspecified time in the future,
+ even if Parse is currently inaccessible.
+
+ @discussion Use this when you may not have a solid network connection, and don't need to know when the save completes.
+ If there is some problem with the object such that it can't be saved, it will be silently discarded. If the save
+ completes successfully while the object is still in memory, then callback will be called.
+
+ Objects saved with this method will be stored locally in an on-disk cache until they can be delivered to Parse.
+ They will be sent immediately if possible. Otherwise, they will be sent the next time a network connection is
+ available. Objects saved this way will persist even after the app is closed, in which case they will be sent the
+ next time the app is opened. If more than 10MB of data is waiting to be sent, subsequent calls to
+ will cause old saves to be silently discarded until the connection can be re-established, and the queued objects
+ can be saved.
+
+ @returns The task that encapsulates the work being done.
+ */
+- (BFTask *)saveEventually;
+
+/*!
+ @abstract Saves this object to the server at some unspecified time in the future,
+ even if Parse is currently inaccessible.
+
+ @discussion Use this when you may not have a solid network connection, and don't need to know when the save completes.
+ If there is some problem with the object such that it can't be saved, it will be silently discarded. If the save
+ completes successfully while the object is still in memory, then callback will be called.
+
+ Objects saved with this method will be stored locally in an on-disk cache until they can be delivered to Parse.
+ They will be sent immediately if possible. Otherwise, they will be sent the next time a network connection is
+ available. Objects saved this way will persist even after the app is closed, in which case they will be sent the
+ next time the app is opened. If more than 10MB of data is waiting to be sent, subsequent calls to
+ will cause old saves to be silently discarded until the connection can be re-established, and the queued objects
+ can be saved.
+
+ @param callback The block to execute.
+ It should have the following argument signature: `^(BOOL succeeded, NSError *error)`.
+ */
+- (void)saveEventually:(PF_NULLABLE PFBooleanResultBlock)callback;
+
+///--------------------------------------
+/// @name Saving Many Objects
+///--------------------------------------
+
+/*!
+ @abstract Saves a collection of objects *synchronously all at once.
+
+ @param objects The array of objects to save.
+
+ @returns Returns whether the save succeeded.
+ */
++ (BOOL)saveAll:(PF_NULLABLE NSArray *)objects;
+
+/*!
+ @abstract Saves a collection of objects *synchronously* all at once and sets an error if necessary.
+
+ @param objects The array of objects to save.
+ @param error Pointer to an `NSError` that will be set if necessary.
+
+ @returns Returns whether the save succeeded.
+ */
++ (BOOL)saveAll:(PF_NULLABLE NSArray *)objects error:(NSError **)error;
+
+/*!
+ @abstract Saves a collection of objects all at once *asynchronously*.
+
+ @param objects The array of objects to save.
+
+ @returns The task that encapsulates the work being done.
+ */
++ (BFTask *)saveAllInBackground:(PF_NULLABLE NSArray *)objects;
+
+/*!
+ @abstract Saves a collection of objects all at once `asynchronously` and executes the block when done.
+
+ @param objects The array of objects to save.
+ @param block The block to execute.
+ It should have the following argument signature: `^(BOOL succeeded, NSError *error)`.
+ */
++ (void)saveAllInBackground:(PF_NULLABLE NSArray *)objects
+ block:(PF_NULLABLE PFBooleanResultBlock)block;
+
+/*
+ @abstract Saves a collection of objects all at once *asynchronously* and calls a callback when done.
+
+ @param objects The array of objects to save.
+ @param target The object to call selector on.
+ @param selector The selector to call.
+ It should have the following signature: `(void)callbackWithResult:(NSNumber *)number error:(NSError *)error`.
+ `error` will be `nil` on success and set if there was an error.
+ `[result boolValue]` will tell you whether the call succeeded or not.
+ */
++ (void)saveAllInBackground:(PF_NULLABLE NSArray *)objects
+ target:(PF_NULLABLE_S id)target
+ selector:(PF_NULLABLE_S SEL)selector;
+
+///--------------------------------------
+/// @name Deleting Many Objects
+///--------------------------------------
+
+/*!
+ @abstract *Synchronously* deletes a collection of objects all at once.
+
+ @param objects The array of objects to delete.
+
+ @returns Returns whether the delete succeeded.
+ */
++ (BOOL)deleteAll:(PF_NULLABLE NSArray *)objects;
+
+/*!
+ @abstract *Synchronously* deletes a collection of objects all at once and sets an error if necessary.
+
+ @param objects The array of objects to delete.
+ @param error Pointer to an `NSError` that will be set if necessary.
+
+ @returns Returns whether the delete succeeded.
+ */
++ (BOOL)deleteAll:(PF_NULLABLE NSArray *)objects error:(NSError **)error;
+
+/*!
+ @abstract Deletes a collection of objects all at once asynchronously.
+ @param objects The array of objects to delete.
+ @returns The task that encapsulates the work being done.
+ */
++ (BFTask *)deleteAllInBackground:(PF_NULLABLE NSArray *)objects;
+
+/*!
+ @abstract Deletes a collection of objects all at once *asynchronously* and executes the block when done.
+
+ @param objects The array of objects to delete.
+ @param block The block to execute.
+ It should have the following argument signature: `^(BOOL succeeded, NSError *error)`.
+ */
++ (void)deleteAllInBackground:(PF_NULLABLE NSArray *)objects
+ block:(PF_NULLABLE PFBooleanResultBlock)block;
+
+/*
+ @abstract Deletes a collection of objects all at once *asynchronously* and calls a callback when done.
+
+ @param objects The array of objects to delete.
+ @param target The object to call selector on.
+ @param selector The selector to call.
+ It should have the following signature: `(void)callbackWithResult:(NSNumber *)number error:(NSError *)error`.
+ `error` will be `nil` on success and set if there was an error.
+ `[result boolValue]` will tell you whether the call succeeded or not.
+ */
++ (void)deleteAllInBackground:(PF_NULLABLE NSArray *)objects
+ target:(PF_NULLABLE_S id)target
+ selector:(PF_NULLABLE_S SEL)selector;
+
+///--------------------------------------
+/// @name Getting an Object
+///--------------------------------------
+
+/*!
+ @abstract Gets whether the `PFObject` has been fetched.
+
+ @returns `YES` if the PFObject is new or has been fetched or refreshed, otherwise `NO`.
+ */
+- (BOOL)isDataAvailable;
+
+#if PARSE_IOS_ONLY
+
+/*!
+ @abstract Refreshes the PFObject with the current data from the server.
+
+ @deprecated Please use `-fetch` instead.
+ */
+- (void)refresh PARSE_DEPRECATED("Please use `-fetch` instead.");
+
+/*!
+ @abstract *Synchronously* refreshes the `PFObject` with the current data from the server and sets an error if it occurs.
+
+ @param error Pointer to an `NSError` that will be set if necessary.
+
+ @deprecated Please use `-fetch:` instead.
+ */
+- (void)refresh:(NSError **)error PARSE_DEPRECATED("Please use `-fetch:` instead.");
+
+/*!
+ @abstract *Asynchronously* refreshes the `PFObject` and executes the given callback block.
+
+ @param block The block to execute.
+ The block should have the following argument signature: `^(PFObject *object, NSError *error)`
+
+ @deprecated Please use `-fetchInBackgroundWithBlock:` instead.
+ */
+- (void)refreshInBackgroundWithBlock:(PF_NULLABLE PFObjectResultBlock)block PARSE_DEPRECATED("Please use `-fetchInBackgroundWithBlock:` instead.");
+
+/*
+ @abstract *Asynchronously* refreshes the `PFObject` and calls the given callback.
+
+ @param target The target on which the selector will be called.
+ @param selector The selector to call.
+ It should have the following signature: `(void)callbackWithResult:(PFObject *)refreshedObject error:(NSError *)error`.
+ `error` will be `nil` on success and set if there was an error.
+ `refreshedObject` will be the `PFObject` with the refreshed data.
+
+ @deprecated Please use `fetchInBackgroundWithTarget:selector:` instead.
+ */
+- (void)refreshInBackgroundWithTarget:(PF_NULLABLE_S id)target
+ selector:(PF_NULLABLE_S SEL)selector PARSE_DEPRECATED("Please use `fetchInBackgroundWithTarget:selector:` instead.");
+
+#endif
+
+/*!
+ @abstract *Synchronously* fetches the PFObject with the current data from the server.
+ */
+- (void)fetch;
+/*!
+ @abstract *Synchronously* fetches the PFObject with the current data from the server and sets an error if it occurs.
+
+ @param error Pointer to an `NSError` that will be set if necessary.
+ */
+- (void)fetch:(NSError **)error;
+
+/*!
+ @abstract *Synchronously* fetches the `PFObject` data from the server if is `NO`.
+ */
+- (PF_NULLABLE PFObject *)fetchIfNeeded;
+
+/*!
+ @abstract *Synchronously* fetches the `PFObject` data from the server if is `NO`.
+
+ @param error Pointer to an `NSError` that will be set if necessary.
+ */
+- (PF_NULLABLE PFObject *)fetchIfNeeded:(NSError **)error;
+
+/*!
+ @abstract Fetches the `PFObject` *asynchronously* and sets it as a result for the task.
+
+ @returns The task that encapsulates the work being done.
+ */
+- (BFTask *)fetchInBackground;
+
+/*!
+ @abstract Fetches the PFObject *asynchronously* and executes the given callback block.
+
+ @param block The block to execute.
+ It should have the following argument signature: `^(PFObject *object, NSError *error)`.
+ */
+- (void)fetchInBackgroundWithBlock:(PF_NULLABLE PFObjectResultBlock)block;
+
+/*
+ @abstract Fetches the `PFObject *asynchronously* and calls the given callback.
+
+ @param target The target on which the selector will be called.
+ @param selector The selector to call.
+ It should have the following signature: `(void)callbackWithResult:(PFObject *)refreshedObject error:(NSError *)error`.
+ `error` will be `nil` on success and set if there was an error.
+ `refreshedObject` will be the `PFObject` with the refreshed data.
+ */
+- (void)fetchInBackgroundWithTarget:(PF_NULLABLE_S id)target selector:(PF_NULLABLE_S SEL)selector;
+
+/*!
+ @abstract Fetches the `PFObject` data *asynchronously* if isDataAvailable is `NO`,
+ then sets it as a result for the task.
+
+ @returns The task that encapsulates the work being done.
+ */
+- (BFTask *)fetchIfNeededInBackground;
+
+/*!
+ @abstract Fetches the `PFObject` data *asynchronously* if is `NO`, then calls the callback block.
+
+ @param block The block to execute.
+ It should have the following argument signature: `^(PFObject *object, NSError *error)`.
+ */
+- (void)fetchIfNeededInBackgroundWithBlock:(PF_NULLABLE PFObjectResultBlock)block;
+
+/*
+ @abstract Fetches the PFObject's data asynchronously if isDataAvailable is false, then calls the callback.
+
+ @param target The target on which the selector will be called.
+ @param selector The selector to call.
+ It should have the following signature: `(void)callbackWithResult:(PFObject *)fetchedObject error:(NSError *)error`.
+ `error` will be `nil` on success and set if there was an error.
+ `refreshedObject` will be the `PFObject` with the refreshed data.
+ */
+- (void)fetchIfNeededInBackgroundWithTarget:(PF_NULLABLE_S id)target
+ selector:(PF_NULLABLE_S SEL)selector;
+
+///--------------------------------------
+/// @name Getting Many Objects
+///--------------------------------------
+
+/*!
+ @abstract *Synchronously* fetches all of the `PFObject` objects with the current data from the server.
+
+ @param objects The list of objects to fetch.
+ */
++ (void)fetchAll:(PF_NULLABLE NSArray *)objects;
+
+/*!
+ @abstract *Synchronously* fetches all of the `PFObject` objects with the current data from the server
+ and sets an error if it occurs.
+
+ @param objects The list of objects to fetch.
+ @param error Pointer to an `NSError` that will be set if necessary.
+ */
++ (void)fetchAll:(PF_NULLABLE NSArray *)objects error:(NSError **)error;
+
+/*!
+ @abstract *Synchronously* fetches all of the `PFObject` objects with the current data from the server.
+ @param objects The list of objects to fetch.
+ */
++ (void)fetchAllIfNeeded:(PF_NULLABLE NSArray *)objects;
+
+/*!
+ @abstract *Synchronously* fetches all of the `PFObject` objects with the current data from the server
+ and sets an error if it occurs.
+
+ @param objects The list of objects to fetch.
+ @param error Pointer to an `NSError` that will be set if necessary.
+ */
++ (void)fetchAllIfNeeded:(PF_NULLABLE NSArray *)objects error:(NSError **)error;
+
+/*!
+ @abstract Fetches all of the `PFObject` objects with the current data from the server *asynchronously*.
+
+ @param objects The list of objects to fetch.
+
+ @returns The task that encapsulates the work being done.
+ */
++ (BFTask *)fetchAllInBackground:(PF_NULLABLE NSArray *)objects;
+
+/*!
+ @abstract Fetches all of the `PFObject` objects with the current data from the server *asynchronously*
+ and calls the given block.
+
+ @param objects The list of objects to fetch.
+ @param block The block to execute.
+ It should have the following argument signature: `^(NSArray *objects, NSError *error)`.
+ */
++ (void)fetchAllInBackground:(PF_NULLABLE NSArray *)objects
+ block:(PF_NULLABLE PFArrayResultBlock)block;
+
+/*
+ @abstract Fetches all of the `PFObject` objects with the current data from the server *asynchronously*
+ and calls the given callback.
+
+ @param objects The list of objects to fetch.
+ @param target The target on which the selector will be called.
+ @param selector The selector to call.
+ It should have the following signature: `(void)callbackWithResult:(NSArray *)fetchedObjects error:(NSError *)error`.
+ `error` will be `nil` on success and set if there was an error.
+ `fetchedObjects` will the array of `PFObject` objects that were fetched.
+ */
++ (void)fetchAllInBackground:(PF_NULLABLE NSArray *)objects
+ target:(PF_NULLABLE_S id)target
+ selector:(PF_NULLABLE_S SEL)selector;
+
+/*!
+ @abstract Fetches all of the `PFObject` objects with the current data from the server *asynchronously*.
+
+ @param objects The list of objects to fetch.
+
+ @returns The task that encapsulates the work being done.
+ */
++ (BFTask *)fetchAllIfNeededInBackground:(PF_NULLABLE NSArray *)objects;
+
+/*!
+ @abstract Fetches all of the PFObjects with the current data from the server *asynchronously*
+ and calls the given block.
+
+ @param objects The list of objects to fetch.
+ @param block The block to execute.
+ It should have the following argument signature: `^(NSArray *objects, NSError *error)`.
+ */
++ (void)fetchAllIfNeededInBackground:(PF_NULLABLE NSArray *)objects
+ block:(PF_NULLABLE PFArrayResultBlock)block;
+
+/*
+ @abstract Fetches all of the PFObjects with the current data from the server *asynchronously*
+ and calls the given callback.
+
+ @param objects The list of objects to fetch.
+ @param target The target on which the selector will be called.
+ @param selector The selector to call.
+ It should have the following signature: `(void)callbackWithResult:(NSArray *)fetchedObjects error:(NSError *)error`.
+ `error` will be `nil` on success and set if there was an error.
+ `fetchedObjects` will the array of `PFObject` objects that were fetched.
+ */
++ (void)fetchAllIfNeededInBackground:(PF_NULLABLE NSArray *)objects
+ target:(PF_NULLABLE_S id)target
+ selector:(PF_NULLABLE_S SEL)selector;
+
+///--------------------------------------
+/// @name Fetching From Local Datastore
+///--------------------------------------
+
+/*!
+ @abstract *Synchronously* loads data from the local datastore into this object,
+ if it has not been fetched from the server already.
+ */
+- (void)fetchFromLocalDatastore;
+
+/*!
+ @abstract *Synchronously* loads data from the local datastore into this object, if it has not been fetched
+ from the server already.
+
+ @discussion If the object is not stored in the local datastore, this `error` will be set to
+ return kPFErrorCacheMiss.
+
+ @param error Pointer to an `NSError` that will be set if necessary.
+ */
+- (void)fetchFromLocalDatastore:(NSError **)error;
+
+/*!
+ @abstract *Asynchronously* loads data from the local datastore into this object,
+ if it has not been fetched from the server already.
+
+ @returns The task that encapsulates the work being done.
+ */
+- (BFTask *)fetchFromLocalDatastoreInBackground;
+
+/*!
+ @abstract *Asynchronously* loads data from the local datastore into this object,
+ if it has not been fetched from the server already.
+
+ @param block The block to execute.
+ It should have the following argument signature: `^(PFObject *object, NSError *error)`.
+ */
+- (void)fetchFromLocalDatastoreInBackgroundWithBlock:(PF_NULLABLE PFObjectResultBlock)block;
+
+///--------------------------------------
+/// @name Deleting an Object
+///--------------------------------------
+
+/*!
+ @abstract *Synchronously* deletes the `PFObject`.
+
+ @returns Returns whether the delete succeeded.
+ */
+- (BOOL)delete;
+
+/*!
+ @abstract *Synchronously* deletes the `PFObject` and sets an error if it occurs.
+
+ @param error Pointer to an `NSError` that will be set if necessary.
+
+ @returns Returns whether the delete succeeded.
+ */
+- (BOOL)delete:(NSError **)error;
+
+/*!
+ @abstract Deletes the `PFObject` *asynchronously*.
+
+ @returns The task that encapsulates the work being done.
+ */
+- (BFTask *)deleteInBackground;
+
+/*!
+ @abstract Deletes the `PFObject` *asynchronously* and executes the given callback block.
+
+ @param block The block to execute.
+ It should have the following argument signature: `^(BOOL succeeded, NSError *error)`.
+ */
+- (void)deleteInBackgroundWithBlock:(PF_NULLABLE PFBooleanResultBlock)block;
+
+/*
+ @abstract Deletes the `PFObject` *asynchronously* and calls the given callback.
+
+ @param target The object to call selector on.
+ @param selector The selector to call.
+ It should have the following signature: `(void)callbackWithResult:(NSNumber *)result error:(NSError *)error`.
+ `error` will be `nil` on success and set if there was an error.
+ `[result boolValue]` will tell you whether the call succeeded or not.
+ */
+- (void)deleteInBackgroundWithTarget:(PF_NULLABLE_S id)target
+ selector:(PF_NULLABLE_S SEL)selector;
+
+/*!
+ @abstract Deletes this object from the server at some unspecified time in the future,
+ even if Parse is currently inaccessible.
+
+ @discussion Use this when you may not have a solid network connection,
+ and don't need to know when the delete completes. If there is some problem with the object
+ such that it can't be deleted, the request will be silently discarded.
+
+ Delete instructions made with this method will be stored locally in an on-disk cache until they can be transmitted
+ to Parse. They will be sent immediately if possible. Otherwise, they will be sent the next time a network connection
+ is available. Delete requests will persist even after the app is closed, in which case they will be sent the
+ next time the app is opened. If more than 10MB of or commands are waiting
+ to be sent, subsequent calls to or will cause old requests to be silently discarded
+ until the connection can be re-established, and the queued requests can go through.
+
+ @returns The task that encapsulates the work being done.
+ */
+- (BFTask *)deleteEventually;
+
+///--------------------------------------
+/// @name Dirtiness
+///--------------------------------------
+
+/*!
+ @abstract Gets whether any key-value pair in this object (or its children)
+ has been added/updated/removed and not saved yet.
+
+ @returns Returns whether this object has been altered and not saved yet.
+ */
+- (BOOL)isDirty;
+
+/*!
+ @abstract Get whether a value associated with a key has been added/updated/removed and not saved yet.
+
+ @param key The key to check for
+
+ @returns Returns whether this key has been altered and not saved yet.
+ */
+- (BOOL)isDirtyForKey:(NSString *)key;
+
+
+///--------------------------------------
+/// @name Pinning
+///--------------------------------------
+
+/*!
+ @abstract *Synchronously* stores the object and every object it points to in the local datastore, recursively,
+ using a default pin name: `PFObjectDefaultPin`.
+
+ @discussion If those other objects have not been fetched from Parse, they will not be stored. However,
+ if they have changed data, all the changes will be retained. To get the objects back later, you can
+ use a that uses <[PFQuery fromLocalDatastore]>, or you can create an unfetched pointer with
+ <[PFObject objectWithoutDataWithClassName:objectId:]> and then call on it.
+
+ @returns Returns whether the pin succeeded.
+
+ @see unpin:
+ @see PFObjectDefaultPin
+ */
+- (BOOL)pin;
+
+/*!
+ @abstract *Synchronously* stores the object and every object it points to in the local datastore, recursively,
+ using a default pin name: `PFObjectDefaultPin`.
+
+ @discussion If those other objects have not been fetched from Parse, they will not be stored. However,
+ if they have changed data, all the changes will be retained. To get the objects back later, you can
+ use a that uses <[PFQuery fromLocalDatastore]>, or you can create an unfetched pointer with
+ <[PFObject objectWithoutDataWithClassName:objectId:]> and then call on it.
+
+ @param error Pointer to an `NSError` that will be set if necessary.
+
+ @returns Returns whether the pin succeeded.
+
+ @see unpin:
+ @see PFObjectDefaultPin
+ */
+- (BOOL)pin:(NSError **)error;
+
+/*!
+ @abstract *Synchronously* stores the object and every object it points to in the local datastore, recursively.
+
+ @discussion If those other objects have not been fetched from Parse, they will not be stored. However,
+ if they have changed data, all the changes will be retained. To get the objects back later, you can
+ use a that uses <[PFQuery fromLocalDatastore]>, or you can create an unfetched pointer with
+ <[PFObject objectWithoutDataWithClassName:objectId:]> and then call on it.
+
+ @param name The name of the pin.
+
+ @returns Returns whether the pin succeeded.
+
+ @see unpinWithName:
+ */
+- (BOOL)pinWithName:(NSString *)name;
+
+/*!
+ @abstract *Synchronously* stores the object and every object it points to in the local datastore, recursively.
+
+ @discussion If those other objects have not been fetched from Parse, they will not be stored. However,
+ if they have changed data, all the changes will be retained. To get the objects back later, you can
+ use a that uses <[PFQuery fromLocalDatastore]>, or you can create an unfetched pointer with
+ <[PFObject objectWithoutDataWithClassName:objectId:]> and then call on it.
+
+ @param name The name of the pin.
+ @param error Pointer to an `NSError` that will be set if necessary.
+
+ @returns Returns whether the pin succeeded.
+
+ @see unpinWithName:
+ */
+- (BOOL)pinWithName:(NSString *)name
+ error:(NSError **)error;
+
+/*!
+ @abstract *Asynchronously* stores the object and every object it points to in the local datastore, recursively,
+ using a default pin name: `PFObjectDefaultPin`.
+
+ @discussion If those other objects have not been fetched from Parse, they will not be stored. However,
+ if they have changed data, all the changes will be retained. To get the objects back later, you can
+ use a that uses <[PFQuery fromLocalDatastore]>, or you can create an unfetched pointer with
+ <[PFObject objectWithoutDataWithClassName:objectId:]> and then call on it.
+
+ @returns The task that encapsulates the work being done.
+
+ @see unpinInBackground
+ @see PFObjectDefaultPin
+ */
+- (BFTask *)pinInBackground;
+
+/*!
+ @abstract *Asynchronously* stores the object and every object it points to in the local datastore, recursively,
+ using a default pin name: `PFObjectDefaultPin`.
+
+ @discussion If those other objects have not been fetched from Parse, they will not be stored. However,
+ if they have changed data, all the changes will be retained. To get the objects back later, you can
+ use a that uses <[PFQuery fromLocalDatastore]>, or you can create an unfetched pointer with
+ <[PFObject objectWithoutDataWithClassName:objectId:]> and then call on it.
+
+ @param block The block to execute.
+ It should have the following argument signature: `^(BOOL succeeded, NSError *error)`.
+
+ @see unpinInBackgroundWithBlock:
+ @see PFObjectDefaultPin
+ */
+- (void)pinInBackgroundWithBlock:(PF_NULLABLE PFBooleanResultBlock)block;
+
+/*!
+ @abstract *Asynchronously* stores the object and every object it points to in the local datastore, recursively.
+
+ @discussion If those other objects have not been fetched from Parse, they will not be stored. However,
+ if they have changed data, all the changes will be retained. To get the objects back later, you can
+ use a that uses <[PFQuery fromLocalDatastore]>, or you can create an unfetched pointer with
+ <[PFObject objectWithoutDataWithClassName:objectId:]> and then call on it.
+
+ @param name The name of the pin.
+
+ @returns The task that encapsulates the work being done.
+
+ @see unpinInBackgroundWithName:
+ */
+- (BFTask *)pinInBackgroundWithName:(NSString *)name;
+
+/*!
+ @abstract *Asynchronously* stores the object and every object it points to in the local datastore, recursively.
+
+ @discussion If those other objects have not been fetched from Parse, they will not be stored. However,
+ if they have changed data, all the changes will be retained. To get the objects back later, you can
+ use a that uses <[PFQuery fromLocalDatastore]>, or you can create an unfetched pointer with
+ <[PFObject objectWithoutDataWithClassName:objectId:]> and then call on it.
+
+ @param name The name of the pin.
+ @param block The block to execute.
+ It should have the following argument signature: `^(BOOL succeeded, NSError *error)`.
+
+ @see unpinInBackgroundWithName:block:
+ */
+- (void)pinInBackgroundWithName:(NSString *)name block:(PF_NULLABLE PFBooleanResultBlock)block;
+
+///--------------------------------------
+/// @name Pinning Many Objects
+///--------------------------------------
+
+/*!
+ @abstract *Synchronously* stores the objects and every object they point to in the local datastore, recursively,
+ using a default pin name: `PFObjectDefaultPin`.
+
+ @discussion If those other objects have not been fetched from Parse, they will not be stored. However,
+ if they have changed data, all the changes will be retained. To get the objects back later, you can
+ use a that uses <[PFQuery fromLocalDatastore]>, or you can create an unfetched pointer with
+ `[PFObject objectWithoutDataWithClassName:objectId:]` and then call `fetchFromLocalDatastore:` on it.
+
+ @param objects The objects to be pinned.
+
+ @returns Returns whether the pin succeeded.
+
+ @see unpinAll:
+ @see PFObjectDefaultPin
+ */
++ (BOOL)pinAll:(PF_NULLABLE NSArray *)objects;
+
+/*!
+ @abstract *Synchronously* stores the objects and every object they point to in the local datastore, recursively,
+ using a default pin name: `PFObjectDefaultPin`.
+
+ @discussion If those other objects have not been fetched from Parse, they will not be stored. However,
+ if they have changed data, all the changes will be retained. To get the objects back later, you can
+ use a that uses <[PFQuery fromLocalDatastore]>, or you can create an unfetched pointer with
+ `[PFObject objectWithoutDataWithClassName:objectId:]` and then call `fetchFromLocalDatastore:` on it.
+
+ @param objects The objects to be pinned.
+ @param error Pointer to an `NSError` that will be set if necessary.
+
+ @returns Returns whether the pin succeeded.
+
+ @see unpinAll:error:
+ @see PFObjectDefaultPin
+ */
++ (BOOL)pinAll:(PF_NULLABLE NSArray *)objects error:(NSError **)error;
+
+/*!
+ @abstract *Synchronously* stores the objects and every object they point to in the local datastore, recursively.
+
+ @discussion If those other objects have not been fetched from Parse, they will not be stored. However,
+ if they have changed data, all the changes will be retained. To get the objects back later, you can
+ use a that uses <[PFQuery fromLocalDatastore]>, or you can create an unfetched pointer with
+ `[PFObject objectWithoutDataWithClassName:objectId:]` and then call `fetchFromLocalDatastore:` on it.
+
+ @param objects The objects to be pinned.
+ @param name The name of the pin.
+
+ @returns Returns whether the pin succeeded.
+
+ @see unpinAll:withName:
+ */
++ (BOOL)pinAll:(PF_NULLABLE NSArray *)objects withName:(NSString *)name;
+
+/*!
+ @abstract *Synchronously* stores the objects and every object they point to in the local datastore, recursively.
+
+ @discussion If those other objects have not been fetched from Parse, they will not be stored. However,
+ if they have changed data, all the changes will be retained. To get the objects back later, you can
+ use a that uses <[PFQuery fromLocalDatastore]>, or you can create an unfetched pointer with
+ `[PFObject objectWithoutDataWithClassName:objectId:]` and then call `fetchFromLocalDatastore:` on it.
+
+ @param objects The objects to be pinned.
+ @param name The name of the pin.
+ @param error Pointer to an `NSError` that will be set if necessary.
+
+ @returns Returns whether the pin succeeded.
+
+ @see unpinAll:withName:error:
+ */
++ (BOOL)pinAll:(PF_NULLABLE NSArray *)objects
+ withName:(NSString *)name
+ error:(NSError **)error;
+
+/*!
+ @abstract *Asynchronously* stores the objects and every object they point to in the local datastore, recursively,
+ using a default pin name: `PFObjectDefaultPin`.
+
+ @discussion If those other objects have not been fetched from Parse, they will not be stored. However,
+ if they have changed data, all the changes will be retained. To get the objects back later, you can
+ use a that uses <[PFQuery fromLocalDatastore]>, or you can create an unfetched pointer with
+ `[PFObject objectWithoutDataWithClassName:objectId:]` and then call `fetchFromLocalDatastore:` on it.
+
+ @param objects The objects to be pinned.
+
+ @returns The task that encapsulates the work being done.
+
+ @see unpinAllInBackground:
+ @see PFObjectDefaultPin
+ */
++ (BFTask *)pinAllInBackground:(PF_NULLABLE NSArray *)objects;
+
+/*!
+ @abstract *Asynchronously* stores the objects and every object they point to in the local datastore, recursively,
+ using a default pin name: `PFObjectDefaultPin`.
+
+ @discussion If those other objects have not been fetched from Parse, they will not be stored. However,
+ if they have changed data, all the changes will be retained. To get the objects back later, you can
+ use a that uses <[PFQuery fromLocalDatastore]>, or you can create an unfetched pointer with
+ `[PFObject objectWithoutDataWithClassName:objectId:]` and then call `fetchFromLocalDatastore:` on it.
+
+ @param objects The objects to be pinned.
+ @param block The block to execute.
+ It should have the following argument signature: `^(BOOL succeeded, NSError *error)`.
+
+ @see unpinAllInBackground:block:
+ @see PFObjectDefaultPin
+ */
++ (void)pinAllInBackground:(PF_NULLABLE NSArray *)objects block:(PF_NULLABLE PFBooleanResultBlock)block;
+
+/*!
+ @abstract *Asynchronously* stores the objects and every object they point to in the local datastore, recursively.
+
+ @discussion If those other objects have not been fetched from Parse, they will not be stored. However,
+ if they have changed data, all the changes will be retained. To get the objects back later, you can
+ use a that uses <[PFQuery fromLocalDatastore]>, or you can create an unfetched pointer with
+ `[PFObject objectWithoutDataWithClassName:objectId:]` and then call `fetchFromLocalDatastore:` on it.
+
+ @param objects The objects to be pinned.
+ @param name The name of the pin.
+
+ @returns The task that encapsulates the work being done.
+
+ @see unpinAllInBackground:withName:
+ */
++ (BFTask *)pinAllInBackground:(PF_NULLABLE NSArray *)objects withName:(NSString *)name;
+
+/*!
+ @abstract *Asynchronously* stores the objects and every object they point to in the local datastore, recursively.
+
+ @discussion If those other objects have not been fetched from Parse, they will not be stored. However,
+ if they have changed data, all the changes will be retained. To get the objects back later, you can
+ use a that uses <[PFQuery fromLocalDatastore]>, or you can create an unfetched pointer with
+ `[PFObject objectWithoutDataWithClassName:objectId:]` and then call `fetchFromLocalDatastore:` on it.
+
+ @param objects The objects to be pinned.
+ @param name The name of the pin.
+ @param block The block to execute.
+ It should have the following argument signature: `^(BOOL succeeded, NSError *error)`.
+
+ @see unpinAllInBackground:withName:block:
+ */
++ (void)pinAllInBackground:(PF_NULLABLE NSArray *)objects
+ withName:(NSString *)name
+ block:(PF_NULLABLE PFBooleanResultBlock)block;
+
+///--------------------------------------
+/// @name Unpinning
+///--------------------------------------
+
+/*!
+ @abstract *Synchronously* removes the object and every object it points to in the local datastore, recursively,
+ using a default pin name: `PFObjectDefaultPin`.
+
+ @returns Returns whether the unpin succeeded.
+
+ @see pin:
+ @see PFObjectDefaultPin
+ */
+- (BOOL)unpin;
+
+/*!
+ @abstract *Synchronously* removes the object and every object it points to in the local datastore, recursively,
+ using a default pin name: `PFObjectDefaultPin`.
+
+ @param error Pointer to an `NSError` that will be set if necessary.
+
+ @returns Returns whether the unpin succeeded.
+
+ @see pin:
+ @see PFObjectDefaultPin
+ */
+- (BOOL)unpin:(NSError **)error;
+
+/*!
+ @abstract *Synchronously* removes the object and every object it points to in the local datastore, recursively.
+
+ @param name The name of the pin.
+
+ @returns Returns whether the unpin succeeded.
+
+ @see pinWithName:
+ */
+- (BOOL)unpinWithName:(NSString *)name;
+
+/*!
+ @abstract *Synchronously* removes the object and every object it points to in the local datastore, recursively.
+
+ @param name The name of the pin.
+ @param error Pointer to an `NSError` that will be set if necessary.
+
+ @returns Returns whether the unpin succeeded.
+
+ @see pinWithName:error:
+ */
+- (BOOL)unpinWithName:(NSString *)name
+ error:(NSError **)error;
+
+/*!
+ @abstract *Asynchronously* removes the object and every object it points to in the local datastore, recursively,
+ using a default pin name: `PFObjectDefaultPin`.
+
+ @returns The task that encapsulates the work being done.
+
+ @see pinInBackground
+ @see PFObjectDefaultPin
+ */
+- (BFTask *)unpinInBackground;
+
+/*!
+ @abstract *Asynchronously* removes the object and every object it points to in the local datastore, recursively,
+ using a default pin name: `PFObjectDefaultPin`.
+
+ @param block The block to execute.
+ It should have the following argument signature: `^(BOOL succeeded, NSError *error)`.
+
+ @see pinInBackgroundWithBlock:
+ @see PFObjectDefaultPin
+ */
+- (void)unpinInBackgroundWithBlock:(PF_NULLABLE PFBooleanResultBlock)block;
+
+/*!
+ @abstract *Asynchronously* removes the object and every object it points to in the local datastore, recursively.
+
+ @param name The name of the pin.
+
+ @returns The task that encapsulates the work being done.
+
+ @see pinInBackgroundWithName:
+ */
+- (BFTask *)unpinInBackgroundWithName:(NSString *)name;
+
+/*!
+ @abstract *Asynchronously* removes the object and every object it points to in the local datastore, recursively.
+
+ @param name The name of the pin.
+ @param block The block to execute.
+ It should have the following argument signature: `^(BOOL succeeded, NSError *error)`.
+
+ @see pinInBackgroundWithName:block:
+ */
+- (void)unpinInBackgroundWithName:(NSString *)name block:(PF_NULLABLE PFBooleanResultBlock)block;
+
+///--------------------------------------
+/// @name Unpinning Many Objects
+///--------------------------------------
+
+/*!
+ @abstract *Synchronously* removes all objects in the local datastore
+ using a default pin name: `PFObjectDefaultPin`.
+
+ @returns Returns whether the unpin succeeded.
+
+ @see PFObjectDefaultPin
+ */
++ (BOOL)unpinAllObjects;
+
+/*!
+ @abstract *Synchronously* removes all objects in the local datastore
+ using a default pin name: `PFObjectDefaultPin`.
+
+ @param error Pointer to an `NSError` that will be set if necessary.
+
+ @returns Returns whether the unpin succeeded.
+
+ @see PFObjectDefaultPin
+ */
++ (BOOL)unpinAllObjects:(NSError **)error;
+
+/*!
+ @abstract *Synchronously* removes all objects with the specified pin name.
+
+ @param name The name of the pin.
+
+ @returns Returns whether the unpin succeeded.
+ */
++ (BOOL)unpinAllObjectsWithName:(NSString *)name;
+
+/*!
+ @abstract *Synchronously* removes all objects with the specified pin name.
+
+ @param name The name of the pin.
+ @param error Pointer to an `NSError` that will be set if necessary.
+
+ @returns Returns whether the unpin succeeded.
+ */
++ (BOOL)unpinAllObjectsWithName:(NSString *)name
+ error:(NSError **)error;
+
+/*!
+ @abstract *Asynchronously* removes all objects in the local datastore
+ using a default pin name: `PFObjectDefaultPin`.
+
+ @returns The task that encapsulates the work being done.
+
+ @see PFObjectDefaultPin
+ */
++ (BFTask *)unpinAllObjectsInBackground;
+
+/*!
+ @abstract *Asynchronously* removes all objects in the local datastore
+ using a default pin name: `PFObjectDefaultPin`.
+
+ @param block The block to execute.
+ It should have the following argument signature: `^(BOOL succeeded, NSError *error)`.
+
+ @see PFObjectDefaultPin
+ */
++ (void)unpinAllObjectsInBackgroundWithBlock:(PF_NULLABLE PFBooleanResultBlock)block;
+
+/*!
+ @abstract *Asynchronously* removes all objects with the specified pin name.
+
+ @param name The name of the pin.
+
+ @returns The task that encapsulates the work being done.
+ */
++ (BFTask *)unpinAllObjectsInBackgroundWithName:(NSString *)name;
+
+/*!
+ @abstract *Asynchronously* removes all objects with the specified pin name.
+
+ @param name The name of the pin.
+ @param block The block to execute.
+ It should have the following argument signature: `^(BOOL succeeded, NSError *error)`.
+ */
++ (void)unpinAllObjectsInBackgroundWithName:(NSString *)name block:(PF_NULLABLE PFBooleanResultBlock)block;
+
+/*!
+ @abstract *Synchronously* removes the objects and every object they point to in the local datastore, recursively,
+ using a default pin name: `PFObjectDefaultPin`.
+
+ @param objects The objects.
+
+ @returns Returns whether the unpin succeeded.
+
+ @see pinAll:
+ @see PFObjectDefaultPin
+ */
++ (BOOL)unpinAll:(PF_NULLABLE NSArray *)objects;
+
+/*!
+ @abstract *Synchronously* removes the objects and every object they point to in the local datastore, recursively,
+ using a default pin name: `PFObjectDefaultPin`.
+
+ @param objects The objects.
+ @param error Pointer to an `NSError` that will be set if necessary.
+
+ @returns Returns whether the unpin succeeded.
+
+ @see pinAll:error:
+ @see PFObjectDefaultPin
+ */
++ (BOOL)unpinAll:(PF_NULLABLE NSArray *)objects error:(NSError **)error;
+
+/*!
+ @abstract *Synchronously* removes the objects and every object they point to in the local datastore, recursively.
+
+ @param objects The objects.
+ @param name The name of the pin.
+
+ @returns Returns whether the unpin succeeded.
+
+ @see pinAll:withName:
+ */
++ (BOOL)unpinAll:(PF_NULLABLE NSArray *)objects withName:(NSString *)name;
+
+/*!
+ @abstract *Synchronously* removes the objects and every object they point to in the local datastore, recursively.
+
+ @param objects The objects.
+ @param name The name of the pin.
+ @param error Pointer to an `NSError` that will be set if necessary.
+
+ @returns Returns whether the unpin succeeded.
+
+ @see pinAll:withName:error:
+ */
++ (BOOL)unpinAll:(PF_NULLABLE NSArray *)objects
+ withName:(NSString *)name
+ error:(NSError **)error;
+
+/*!
+ @abstract *Asynchronously* removes the objects and every object they point to in the local datastore, recursively,
+ using a default pin name: `PFObjectDefaultPin`.
+
+ @param objects The objects.
+
+ @returns The task that encapsulates the work being done.
+
+ @see pinAllInBackground:
+ @see PFObjectDefaultPin
+ */
++ (BFTask *)unpinAllInBackground:(PF_NULLABLE NSArray *)objects;
+
+/*!
+ @abstract *Asynchronously* removes the objects and every object they point to in the local datastore, recursively,
+ using a default pin name: `PFObjectDefaultPin`.
+
+ @param objects The objects.
+ @param block The block to execute.
+ It should have the following argument signature: `^(BOOL succeeded, NSError *error)`.
+
+ @see pinAllInBackground:block:
+ @see PFObjectDefaultPin
+ */
++ (void)unpinAllInBackground:(PF_NULLABLE NSArray *)objects block:(PF_NULLABLE PFBooleanResultBlock)block;
+
+/*!
+ @abstract *Asynchronously* removes the objects and every object they point to in the local datastore, recursively.
+
+ @param objects The objects.
+ @param name The name of the pin.
+
+ @returns The task that encapsulates the work being done.
+
+ @see pinAllInBackground:withName:
+ */
++ (BFTask *)unpinAllInBackground:(PF_NULLABLE NSArray *)objects withName:(NSString *)name;
+
+/*!
+ @abstract *Asynchronously* removes the objects and every object they point to in the local datastore, recursively.
+
+ @param objects The objects.
+ @param name The name of the pin.
+ @param block The block to execute.
+ It should have the following argument signature: `^(BOOL succeeded, NSError *error)`.
+
+ @see pinAllInBackground:withName:block:
+ */
++ (void)unpinAllInBackground:(PF_NULLABLE NSArray *)objects
+ withName:(NSString *)name
+ block:(PF_NULLABLE PFBooleanResultBlock)block;
+
+@end
+
+PF_ASSUME_NONNULL_END
diff --git a/Pods/Parse/PFProduct.h b/Pods/Parse/PFProduct.h
new file mode 100644
index 0000000..939f136
--- /dev/null
+++ b/Pods/Parse/PFProduct.h
@@ -0,0 +1,65 @@
+//
+// PFProduct.h
+//
+// Copyright 2011-present Parse Inc. All rights reserved.
+//
+
+#import
+#import
+#import
+#import
+
+PF_ASSUME_NONNULL_BEGIN
+
+/*!
+ The `PFProduct` class represents an in-app purchase product on the Parse server.
+ By default, products can only be created via the Data Browser. Saving a `PFProduct` will result in error.
+ However, the products' metadata information can be queried and viewed.
+
+ This class is currently for iOS only.
+ */
+@interface PFProduct : PFObject
+
+///--------------------------------------
+/// @name Product-specific Properties
+///--------------------------------------
+
+/*!
+ @abstract The product identifier of the product.
+
+ @discussion This should match the product identifier in iTunes Connect exactly.
+ */
+@property (PF_NULLABLE_PROPERTY nonatomic, strong) NSString *productIdentifier;
+
+/*!
+ @abstract The icon of the product.
+ */
+@property (PF_NULLABLE_PROPERTY nonatomic, strong) PFFile *icon;
+
+/*!
+ @abstract The title of the product.
+ */
+@property (PF_NULLABLE_PROPERTY nonatomic, strong) NSString *title;
+
+/*!
+ @abstract The subtitle of the product.
+ */
+@property (PF_NULLABLE_PROPERTY nonatomic, strong) NSString *subtitle;
+
+/*!
+ @abstract The order in which the product information is displayed in .
+
+ @discussion The product with a smaller order is displayed earlier in the .
+ */
+@property (PF_NULLABLE_PROPERTY nonatomic, strong) NSNumber *order;
+
+/*!
+ @abstract The name of the associated download.
+
+ @discussion If there is no downloadable asset, it should be `nil`.
+ */
+@property (PF_NULLABLE_PROPERTY nonatomic, strong, readonly) NSString *downloadName;
+
+@end
+
+PF_ASSUME_NONNULL_END
diff --git a/Pods/Parse/PFPurchase.h b/Pods/Parse/PFPurchase.h
new file mode 100644
index 0000000..3a8e661
--- /dev/null
+++ b/Pods/Parse/PFPurchase.h
@@ -0,0 +1,87 @@
+//
+// PFPurchase.h
+//
+// Copyright 2011-present Parse Inc. All rights reserved.
+//
+
+#import
+#import